dimanche 20 octobre 2019

Testing behaviour vs implementation

I have been tasked with making a small change to a codebase with no tests and am trying to implement the change using TDD for the first time but am struggling with the difference between testing implementation and behaviour. The system I am working on renders user-configurable list items. User can make changes to a list items behaviour through a global preference system, controlled by an XML DAO:

class Preference {
  boolean getX();
  boolean getY();
}

I have been tasked with adding Z to this DAO, I have implemented this change and added tests to ensure the value serialises and deserialises as I would expect.

The following list item class should then receive the Z value:

class ListItemA extends ListItem {
  private boolean Z;

  ListItemA(boolean Z){
    this.Z = Z;
  }

  OpenAction getOpenAction(){
    OpenAction action = new OpenAction();

    if(Z){
       action.addValue('Filter', true);
    }

    return action;
  }
}

I have also written tests to ensure that the action returned reflects the Z field. The connection between these two is where I am struggling, there is a controller class that is called when rendering the list items:

class Controller {
  private Preference preference;

  Controller(Preference preference){
    this.preference = preference;
  }

  List<ListItem> getListItems(State state){
    // a bunch condition statements concerning the state
    List<ListItem> items = new List();

    if(state.items.includes('ListItemA')){
      ListItemA item = new ListItemA();
    }

    return items;
  }

}

When instantiate ListItemA, I now need to pass getZ() from the preference field but TDD says that I cannot make this change without a failing test first.

I could mock the preference, mock the state, generate the list and then write the same test to ensure the OpenAction reflects the value of Z but this seems as though I am testing implementation and writing a brittle test. In addition there would be a lot of duplicated test code from the ListItem test as they are making the same assertion. Another alternative would be to scrap the ListItem test and add all the assertions in the Controller test but this seems like I am testing another system.

My questions are:

  • How do I draw the line between testing implementation and writing tests that are too broad?

  • How would you approach testing this situation?

  • Am I overtesting?

  • I am approaching changes to this legacy system through TDD, as per the book I have just finished 'Working Effectively in Legacy Code', does the method described above match the process I should be undertaking when approaching a system like this?

  • Are there any good articles, books or resources I can read up on to further my understanding of this area?

  • How do I go about testing a legacy system in a workplace with a no-testing culture? I don't have any legacy systems of my own to work on, how do I gain experience?

Aucun commentaire:

Enregistrer un commentaire