Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I factor code to ease testability?

I am learning about Unit Testing and want to know how to write testable code. But, I'm not sure how to write testable code without making it complex. I'll take famous Car and Engine problem to describe the problem.

class Car
{
private:
   Engine m_engine;

public:
   Car();
   // Rest of the car
}

I came up with following solutions to make the above code testable.

  1. Changing the Car's constructor to take Engine as a parameter. Then mock the Engine and do the testing. But, if I don't have different kinds of Engines, it seems inappropriate to parameterize the constructor just to make it testable.

  2. Using a setter and then pass a mock Engine to the setter. Same flow as the above.

  3. Testing the Engine first and then testing the Car with proven Engine (or using a stub Engine).

What are the alternatives I have to make above code testable? What are the strenghts and weaknesses of each method?

like image 924
Varuna Avatar asked Nov 29 '22 19:11

Varuna


1 Answers

Look at it from a different (Test-Driven Development) viewpoint: code that is easy to test is easy to use. Writing the unit tests is actually you testing the "public interface" of your code. If it's hard to test, that's because you've got some dependencies in there that make it hard. Do you really need a containment relationship, or would an associative relationship make more sense?

In your case I personally think it would be more testable to pass the Engine in the constructor, so I'd refactor the constructor as in your suggestion #1. You can test the Engine in one test suite, and provide a mock Engine to test the Car in another test suite. Testing it is now easy, meaning the interface is easy to use. That's a good thing.

Now think about how you would use that implementation in a real project. You'd create a CarFactory class, and the factory would create an Engine and put it in the Car before delivering it to you. (Also notice how this ends up more closely modeling the real world of cars and engines and factories, but I digress.)

Therefore the TDD answer would be to refactor the code to take an Engine pointer on the constructor.

like image 60
John Deters Avatar answered Dec 11 '22 18:12

John Deters