如何在不重复测试代码的情况下以编程方式测试 UI action/activities?
How to programatically test UI action/activities without repeating test code?
我是 TDD 的新手,尤其是 TFD。我还没有写任何代码,我想先写一个测试,然后再结合 TDD 开发所有东西。我想要你的洞察力。看来我是在复制粘贴我的测试代码。我制作了 'pseudo' 用户故事供我练习。我要解释一下,因为这是一个实际的个人项目,所以请多多包涵。
"User can search for a tag"
我有一个 UI 允许添加和搜索标签。我通过使用最小的设计让它有点保守。我有一个在 add/search 字符串之间切换的按钮。我有一个 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
源自父 activity。在通过 TagListActivity
之前,您需要做一些事情,我已经为它编写了测试。因此,当我测试 TagListActivity
时,我必须首先进入应用程序的主屏幕并从那里导航,正如您从我的测试过程 shouldHaveAddTagCard
中看到的那样。这是我的问题,我必须一遍又一遍地编写该程序。因此,当我想测试 shouldToggleSearch
时,我必须从父 activity 开始并再次编写这些测试,直到达到 TagListActivity
。我想我做错了什么。
所以我的问题是:
- 当有已知的用户操作过程时,我该如何组织它。
我已经为每个程序编写了测试,以确保它能满足我的要求
成为。
- 没有。 1 让我觉得我做的事情有问题。我正在测试每个操作(即用户添加标签、用户搜索标签、用户删除标签)。所以前置程序
我之前做的
user can add tags
和 user can search tag
一样,我有
在我实际测试之前复制粘贴那些预程序。
此外,我似乎无法从讨论的测试方法中调用测试方法 here。我正在考虑重用测试代码,但这是不可取的。
做事正确吗?有什么想法吗?
老实说,如果这是您第一次进行 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
方法很棒,但是,请记住,复制和粘贴测试代码并不总是坏事。这是与生产代码不同的平衡。在生产代码中,您不希望出现重复,因为任何给定的业务逻辑片段都应该只存在于一个地方。然而,在测试代码中,每个测试都需要完全独立于所有其他测试。如果摆脱了测试代码中的 all 重复,那么在不破坏所有测试的情况下更改共享代码将非常困难。此外,您的测试将更难阅读,因为您必须不断参考共享代码。
我建议您对 DAMP(描述性和有意义的短语)与 DRY(不要重复自己)做一些研究。 DAMP 与单元测试更相关,并且允许您有时重复自己。 DRY 与生产代码更相关。以下答案很好地解释了这一点:
我是 TDD 的新手,尤其是 TFD。我还没有写任何代码,我想先写一个测试,然后再结合 TDD 开发所有东西。我想要你的洞察力。看来我是在复制粘贴我的测试代码。我制作了 'pseudo' 用户故事供我练习。我要解释一下,因为这是一个实际的个人项目,所以请多多包涵。
"User can search for a tag"
我有一个 UI 允许添加和搜索标签。我通过使用最小的设计让它有点保守。我有一个在 add/search 字符串之间切换的按钮。我有一个 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
源自父 activity。在通过 TagListActivity
之前,您需要做一些事情,我已经为它编写了测试。因此,当我测试 TagListActivity
时,我必须首先进入应用程序的主屏幕并从那里导航,正如您从我的测试过程 shouldHaveAddTagCard
中看到的那样。这是我的问题,我必须一遍又一遍地编写该程序。因此,当我想测试 shouldToggleSearch
时,我必须从父 activity 开始并再次编写这些测试,直到达到 TagListActivity
。我想我做错了什么。
所以我的问题是:
- 当有已知的用户操作过程时,我该如何组织它。 我已经为每个程序编写了测试,以确保它能满足我的要求 成为。
- 没有。 1 让我觉得我做的事情有问题。我正在测试每个操作(即用户添加标签、用户搜索标签、用户删除标签)。所以前置程序
我之前做的
user can add tags
和user can search tag
一样,我有 在我实际测试之前复制粘贴那些预程序。
此外,我似乎无法从讨论的测试方法中调用测试方法 here。我正在考虑重用测试代码,但这是不可取的。
做事正确吗?有什么想法吗?
老实说,如果这是您第一次进行 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
方法很棒,但是,请记住,复制和粘贴测试代码并不总是坏事。这是与生产代码不同的平衡。在生产代码中,您不希望出现重复,因为任何给定的业务逻辑片段都应该只存在于一个地方。然而,在测试代码中,每个测试都需要完全独立于所有其他测试。如果摆脱了测试代码中的 all 重复,那么在不破坏所有测试的情况下更改共享代码将非常困难。此外,您的测试将更难阅读,因为您必须不断参考共享代码。
我建议您对 DAMP(描述性和有意义的短语)与 DRY(不要重复自己)做一些研究。 DAMP 与单元测试更相关,并且允许您有时重复自己。 DRY 与生产代码更相关。以下答案很好地解释了这一点: