0

I have a class

class A {
  List<int> a;
  A() {
    this.a = [];
  }
  void add(int x) {
    a.append(x)
  }
  List<int> display() {
     return a;
  }
}

This is a simple class I want to write in a TDD approach. my question is how do you write the test for the display() since the add() need to be called to make the test useful.

And it feels wrong to test the function it needs to rely on the other function which requires testing.

How to we handle this?

candied_orange
  • 119,268

2 Answers2

3

TDD doesn’t say you can only call one method. You have setup to do. That’s all. Now sure it means the function under test isn’t the only thing that can cause the test to fail. But that’s true whenever object state is involved. It has to be set by something.

Don’t get so hung up on the structure of you code. When a test fails just be sure it’s not hard to find the failure.

If your state was constant and set by an initializer, rather than constructor or setter, its code would be just as involved.

Remember, the point is to test the interface. Not to lock the class down to any particular structure.

I see at least two tests here. One involves constructor, setter, and getter. One only involves constructor and getter. But that one has to know the default value. Up to you if you really want to lock that down.

candied_orange
  • 119,268
2

I think this is best understood by going through your example (in pseudocode):

  • let us assume class A already exists, by prior work (maybe TDD or not, does not matter), but it does not have add, display and the internal member a.

  • First test:

    TestAfterConstructionReturnedListIsEmpty()
    {
         var a = new A();
         Assert.AreEqual(0, a.display().size());
    }
    

    Now this fails at compilation, since display does not exist. So the next step is to implement the display method. One could go and implement List<int> a; right here, but for demonstration purposes, let us do this in baby steps:

    List<int> display() { return [];}
    

    will make the test pass. There is nothing much to refactor at this stage, so let us continue.

  • Second test:

    TestAddingOneElementThisElementFormsTheList()
    {
       var a = new A();
       a.add(123);
       var result = a.display();
       Assert.AreEqual([123],result.display());
    }
    

    Now, you first have to add the add method to make this compile (an empty implementation will be enough). Then, the test will run, but still fail. So next step is add the minimal amount of code this test will not fail any more (but without making any assumptions of what data is passed in the tests, of course.)

    A very simple implementation could look like this

     class A
     {
        int a;
         void add(int x) {a=x;}
         List<int> display(){return [a];}
     }
    

    But then you will notice that though the second test passes now, the first one will fail.

Hence, at this stage, you will probably add List<int> a to A and complete the implementations of add and display in your code the way scetched in the question, since I can hardly imagine a simpler implementation to fulfill the requirements of both existing tests.

Note TDD does not mean to write one test after another to add one function after another to a class. It is about writing one test after another to add some additional behaviour to a class. This behaviour may involve adding or changing functions or also touching several existing ones.

Doc Brown
  • 218,378