0

I am very new to TDD and doing TFD in particular. I have not written any codes yet and I wanted to write a test first before develop everything in conjunction with TDD. I want your insight. It seems I am copy pasting my test code. I have made my 'pseudo' user story for me to practice. I am going to paraphrase as this is an actual personal project so please bear with me.

"User can search for a tag"

I have a UI that allows to add and to search for a tag. I made it a little bit conservative by using minimal design. I have a button which toggles between add/search string. I have a CardView to represent this, that CardView is part of the list (its like Facebook). Now I wanted to test that when the user press the button, the content on that card will change to search mode. I pretty much have an idea on how to do this but copy pasting my test code per each test is kind of bothering me.

Here is my test:

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()));
    }
}

The TagListActivity is originating from a parent activity. There is some bunch of things you have to do before you can go through the TagListActivity and I already have written test for it. So when I test TagListActivity I have to go first in application's homescreen and navigate from there as you can see from my test procedure shouldHaveAddTagCard. This is my problem, I have to write that procedure over and over again. So when I wanted to test shouldToggleSearch I have to go from the parent activity and write those tests again until I reached TagListActivity. I think I am doing something wrong.

So my question is:

  1. How can I organize this when there is a known user action procedure. I have written test per procedure to make sure it does what I wanted to be.
  2. no. 1 makes me feel there is something wrong in what I am doing. I am testing per action (ie user adds tag, user search tag, user deletes tag). So the pre-procedure I did before user can add tags is the same as user can search tag and I have to copy paste those pre-procedure before I can actually test.

Also, it seems that I cannot call a test method from a test method as discussed here. I am thinking of reusing test code but it is not advisable.

Am doing things correctly? Any thoughts?

Community
  • 1
  • 1
Neon Warge
  • 1,652
  • 4
  • 28
  • 46

1 Answers1

1

To be honest your tests look very good if this is your first time doing TDD.

Reducing duplication

You can use the @Before annotation to execute some code before each test. In your case, it might look something like this:

// 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
}

Bear in mind that, in general, you should not make any assertions in the @Before method. It is for set up code only.

But is it always a good thing?

@Before methods are great, however, remember that copying and pasting test code is not always a bad thing. It's a different balance to production code. In production code, you want no duplication because any given piece of business logic should only exist in one place. In test code however, each test needs to be completely independent from all the other tests. If got rid of all the duplication in your test code, then it would be very difficult to change the shared code without breaking all your tests. Furthermore, your tests would be harder to read because you would have to keep referring to the shared code.

I recommend that you do some research on DAMP (descriptive and meaningful phrases) vs DRY (don't repeat yourself). DAMP is more relevant for unit tests, and allows you to repeat yourself sometimes. DRY is more relevant for production code. The following answer is great at explaining this:

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

Community
  • 1
  • 1
tonicsoft
  • 1,539
  • 6
  • 16
  • Wow thanks for the insight. Its good to know its okay to repeat myself sometimes on test code and not be when on production code. I need to get use to testing environment and there is a lot of adapting to do :p. – Neon Warge Sep 24 '16 at 12:50