开发者

Test-driven Development: Writing tests for private / protected variables

开发者 https://www.devze.com 2023-01-03 19:20 出处:网络
I\'m learning TDD, and I have a question about private / protected variables. My question is: If a function I want to test is operating on a private variable, how should I test it?

I'm learning TDD, and I have a question about private / protected variables. My question is: If a function I want to test is operating on a private variable, how should I test it?

Here is the example I'm working with:

I have a class called Table that contains an instance variable called internalRepresentation that is a 2D array. I want to create a function called multi开发者_开发问答plyValuesByN that multiplies all the values in the 2D array by the argument n.

So I write the test for it (in Python):

def test_multiplyValuesByN (self):  
    t = Table(3, 3) # 3x3 table, filled with 0's
    t.set(0, 0, 4) # Set value at position (0,0) to 4
    t.multiplyValuesByN(3)

    assertEqual(t.internalRepresentation, [[12, 0, 0], [0, 0, 0], [0, 0, 0]])

Now, if I make internalRepresentation private or protected, this test will not work. How am I supposed to write the test so it doesn't depend on internalRepresentation but still tests that it looks correct after calling multiplyValuesByN?


You should not depend on the internal representation of an object. That's why it is marked as private or protected. Consider what observable changes are made to t when you call t.multiplyValuesByN(3). Then, test on what you can observe.

def test_multiplyValuesByN (self):  
    t = Table(3, 3) # 3x3 table, filled with 0's
    t.set(0, 0, 4) # Set value at position (0,0) to 4
    t.multiplyValuesByN(3)

    assertEqual(t.get(0,0), 12)


If it is internal, then it is nobodys business outside the class and that includes the tests.

In TDD you are designing the API of your classes and the future clients also can only see the observable behavior of the class.

I know this is easier said than done.

In test you often see a pattern reoccuring : setup - operate - check (- teardown)

The setup phase is responsible to bring the object in the preconditions state.

The check phase should verify the postconditions through observable behavior of the class. It makes no sense to store invisible state, if it never and nowhere comes out.


Others have posted good answers, but IMHO failed to emphasize one thing: the design aspect (although Peter Tillemans mentioned it). So I add a bit of an explanation on this.

When doing TDD, you are effectively testing the design of your API as well as the implementation. If you find that the result of a method call is difficult or impossible to see from outside, this is almost always a sign that your class interface is not designed well. If it is difficult to write tests for your class, it will usually be difficult to use it in real life too - your unit tests are in effect the first clients of your class. So if you see that a test case has difficulty using your class interface, you should consider going back and redesigning your API to make it easier to use (not compromising encapsulation, if possible).


Don't test for private variables/state. Your tests should confirm that the unit under test conforms to its specification, and that specification is determined by its interface. So your test should be written in terms of the inputs to your test unit, and verify that the output matches what you expect.

You want to be able to change the implementation of the unit under test (for, say, efficiency reasons) and yet confirm that it works as expected. So checking private state would cause difficulties in this situation.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号