2

Assuming I have the following (very simple) class

class Foo
{
  public:
    void setAB(int a, int b) { m_a = a; m_b = b; m_aIsBigger = a > b; }
    int getA() const { return m_a; }
    int getB() const { return m_b; }
    bool isABigger() const { return m_aIsBigger; }

  protected:
    int m_a;
    int m_b;
    bool m_aIsBigger;
}

and I want to put it under automated test (e.g. unit test, module test). I can see two possible ways to test the functions:

Either I can use its own functions to test it, i.e. invoke setAB() and then verify that getA(), getB(), and isABigger() return the expected values. Or I could directly set m_a (e.g. by subclassing Foo), then invoke getA() and verify that the value is identical to the one I set.

The first method seems more "organic", as it uses the class' built-in functionality and is independent of its implementation (e.g. in the case I realize that I could calculate "a > b" on the fly for isABigger() instead of using m_aIsBigger). However it seems to violate the "test only one thing" principle for tests (even if I separate getA(), getB(), and isABigger() in their own test cases, I cannot test them apart from setAB(); nor can I test setAB() without invoking getA()and getB())

If I subclass Foo I can test each function individually, but it feels kinda wrong to manipulate the class' interna this way, and is far more brittle (changing isABigger() to calculate the result on the fly would require a change in the test - even if it feels it should not).

So the question is: what is the better way to set up an object for testing - or is it merely a matter of personal preferrence?

  • Test via the public interface, and make the members private. If something can't be reached from the public interface in a test, it can't be reached from the public interface in use. – Caleth Apr 6 '18 at 10:01
4

Your intuition is correct: Testing through the public methods is better. "Test only one thing" does not mean only exercice a single method, rather it means a test should only verify a single "behavior".

Subclassing Foo in order to set fields manually is an antipattern, since this would couple the test to the implementation details of Foo. You want to test the behavior of Foo without locking the internals.

1

Accessor methods are often used for more than just assigning or retrieving a value. You may want to clamp a float value to just the positive domain before assigning it. Or do a transformation when retrieving a value because it has a smaller memory print when stored in the class (and can assume the transformation cost in terms of performance). Thus, altering the inner data directly may accidentally have side-effects if the rest of the class isn't prepared for malformed data in its attributes.

Besides, the tests should be centered in the public interface of the class (you can test the private/protected interface just to make sure reusing those methods in other parts is safe too, but that's another story). The point here is that no other client will/should access the protected attributes when there is already a public interface (its accessors) for it. So testing the accessors should be at the very least as safe as just testing the attributes themselves.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.