【问题标题】:How to programatically test UI action/activities without repeating test code?如何在不重复测试代码的情况下以编程方式测试 UI 操作/活动?
【发布时间】:2016-09-24 10:19:57
【问题描述】:

我对 TDD 非常陌生,尤其是 TFD。我还没有写任何代码,我想先写一个测试,然后再结合 TDD 开发一切。我想要你的洞察力。看来我正在复制粘贴我的测试代码。我已经制作了我的“伪”用户故事供我练习。我要解释一下,因为这是一个实际的个人项目,所以请多多包涵。

"用户可以搜索标签"

我有一个允许添加和搜索标签的用户界面。我通过使用最小的设计使它有点保守。我有一个在添加/搜索字符串之间切换的按钮。我有一个CardView 来代表这个,CardView 是列表的一部分(就像 Facebook 一样)。现在我想测试当用户按下按钮时,该卡片上的内容将变为搜索模式。我几乎知道如何做到这一点,但是每次测试都复制粘贴我的测试代码有点困扰我。

这是我的测试:

public class TagListActivityTest
{
    @Test
    public void shouldHaveAddTagCard()
    {
        // User tapped to expand the card
        onView(withId(R.id.edittext_description_minimized))
                .perform(click());

        // User sees the expanded card
        onView(withId(R.id.linearlayout_add_note_maximize))
                .check(matches(isDisplayed()));

        // User sees the expanded card's quick action buttons
        onView(withId(R.id.relativelayout_quick_action_button))
                .check(matches(isDisplayed()));

        // User clicks the add tag button
        onView(withId(R.id.imagebutton_tag))
                .perform(click());

        // User sees the tag list
        onView(withId(R.id.coordinatorlayout_tag_list))
                .check(matches(isDisplayed()));

        // User sees the add tag card
        onView(withId(R.id.cardview_add_tag))
                .check(matches(isDisplayed()));
    }

    @Test
    public void shouldToggleToSearch()
    {
        // I am going to do the exact same thing as shouldHaveAddTagCard
        // starting from my parent activity until here...
        onView(withId(R.id.edittext_description_minimized))
                .perform(click());

        onView(withId(R.id.linearlayout_add_note_maximize))
                .check(matches(isDisplayed()));

        onView(withId(R.id.relativelayout_quick_action_button))
                .check(matches(isDisplayed()));

        onView(withId(R.id.imagebutton_tag))
                .perform(click());

        onView(withId(R.id.coordinatorlayout_tag_list))
                .check(matches(isDisplayed()));
    }
}

TagListActivity 源自父活动。在您可以通过TagListActivity 之前,您必须做一些事情,而且我已经对其进行了书面测试。因此,当我测试TagListActivity 时,我必须首先进入应用程序的主屏幕并从那里导航,正如您从我的测试程序shouldHaveAddTagCard 中看到的那样。这是我的问题,我必须一遍又一遍地编写该程序。因此,当我想测试shouldToggleSearch 时,我必须离开父活动并再次编写这些测试,直到达到TagListActivity。我想我做错了什么。

所以我的问题是:

  1. 如果存在已知的用户操作过程,我该如何组织它。 我已经为每个程序编写了测试,以确保它符合我的要求 成为。
  2. 没有。 1让我觉得我在做的事情有问题。我正在测试每个操作(即用户添加标签、用户搜索标签、用户删除标签)。所以前置程序 我之前做的user can add tagsuser can search tag 一样,我有 在我实际测试之前复制粘贴这些前置程序。

此外,我似乎无法从here 讨论的测试方法中调用测试方法。我正在考虑重用测试代码,但不建议这样做。

做事正确吗?有什么想法吗?

【问题讨论】:

    标签: android unit-testing automated-tests android-espresso android-testing


    【解决方案1】:

    说实话,如果这是您第一次做 TDD,那么您的测试看起来非常好。

    减少重复

    您可以使用@Before 注解在每次测试之前执行一些代码。在您的情况下,它可能看起来像这样:

    // this method will be executed before each test
    @Before
    public void clickOnEditTextDescription() {
        onView(withId(R.id.edittext_description_minimized))
                .perform(click());
        // put as much set up code in here as you need
    }
    

    请记住,一般情况下,您不应在 @Before 方法中做出任何断言。它仅用于设置代码。

    但这总是一件好事吗?

    @Before 方法很棒,但是,请记住,复制和粘贴测试代码并不总是一件坏事。这是与生产代码不同的平衡。在生产代码中,您不希望重复,因为任何给定的业务逻辑都应该只存在于一个地方。然而,在测试代码中,每个测试都需要完全独立于所有其他测试。如果在您的测试代码中删除所有重复项,那么在不破坏所有测试的情况下更改共享代码将非常困难。此外,您的测试将更难阅读,因为您必须继续引用共享代码。

    我建议您对 DAMP(描述性和有意义的短语)与 DRY(不要重复自己)进行一些研究。 DAMP 与单元测试更相关,并且允许您有时重复自己。 DRY 与生产代码更相关。以下答案很好地解释了这一点:

    https://stackoverflow.com/a/11837973/6816469

    【讨论】:

    • 哇,感谢您的洞察力。很高兴知道有时可以在测试代码上重复自己,而不是在生产代码上重复自己。我需要习惯测试环境,并且有很多适应要做:p。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    相关资源
    最近更新 更多