How can I code to simplify testing?

I am studying unit testing and want to know how to write test code. But I'm not sure how to write test code without making it complicated. To describe the problem, I will take a known problem with the car and engine.

class Car { private: Engine m_engine; public: Car(); // Rest of the car } 

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

  • Modifying the Car constructor to use Engine as a parameter. Then scoff at the engine and do the testing. But, if I do not have different types of engines, it seems inappropriate to parameterize the constructor to make it testable.

  • Using the setter, then pass the Engine layout to the setter. The same stream as above.

  • Test the engine first, and then check the car with the engine tested (or using the engine plug).

What are the alternatives I have to do with the code being tested? What are the strengths and weaknesses of each method?

+4
source share
8 answers

If you have only one type of engine, why are you trying to make it a new object? If you do not plan to replace the engines, do not create another layer of abstraction. Just make the engine part of the car.

Perhaps you can decompose to reduce complexity rather than reusing components. Nice call. In this case, I would say that 3 is your best bet - confirm your lower-level components, and then use the higher-level code that calls the lower-level objects.

In fact, the Engine will most likely be a bit of a database. And you will want to change your constructors to use a different database (for testing or other reasons), but you can temporarily leave this false.

+5
source

Look at it from a different perspective (Test-Driven Development): easy-to-test code is easy to use. Writing unit tests, you are actually testing the "open interface" of your code. If this is difficult to verify, because you have some dependencies that make work difficult. Do you really need a containment relationship, or do associative relationships make more sense?

In your case, I personally think that it would be more testable to pass Engine in the constructor, so I would reorganize the constructor, as in your proposal # 1. You can test the Engine in one test suite and provide the Engine layout for testing the car in another test suite . Testing is now easy, which means the interface is easy to use. It's good.

Now think about how to use this implementation in a real project. You must create the CarFactory class, and the factory will create the engine and place it in the car before it is delivered. (Also notice how this ends with a more thorough simulation of the real world of cars and engines and factories, but I'm distracted.)

So the answer to TDD would be to reorganize the code to take the Engine pointer to the constructor.

+7
source

Unit Testing, as the name implies, is to test units to confirm that they are working as prescribed. This means that you must test the engine separately.

System testing or integration Testing is testing that they all stick together correctly.

Of course, this is more complicated than just that, but it should point you in the right direction.

+2
source

Option 1 is usually correct.

With the ability to fully control the engine that you give the car, you can check the car v. OK.

You can more easily check how the car behaves with all the different outputs that the engine gives the car. You can also make sure that the car makes the appropriate calls to the engine.

The presence in the designer really makes it clear that the car depends on the operation of the engine. Use it with a dependency injection infrastructure, and the problem with the constructor is actually not a problem.

+2
source

The real question is: what are the requirements? If the goal is to simply implement the Car object, then he doesn’t even need an engine.

Tests should always be related to requirements. Any object model will be some generalization of reality, so the problem is what aspects should be presented.

As soon as you have your requirements, you should write your tests at a general high level. Then the OO project should be implemented so that these tests can be implemented.

+2
source

Mishko Hevery often writes this topic. Here's a presentation from October 2009. He states that the dependency graph must be explicit in the constructor.

It seems inappropriate to parameterize the constructor to make it verifiable

I think a fascinating comment. Under what conditions will conditions, including testability, as part of the design, be inappropriate? The correct landing for verifiability is clearly incorrect, although in practice I have never seen this choice forced. The effectiveness of sacrifices for verifiability ... perhaps in some specific cases. Unified code? I personally would prefer to change the coding standard and gradually bring the obsolete code into line.

+2
source

One of the possibilities in C ++ is to use friendship:

 class Car { private: //for unit testing friend class TestCar; //this class is the unit test suite for the Car class Car(Engine* mockEngine); //this constructor is only used by the TestCar class private: Engine* m_engine; public: Car(); // Rest of the car }; 

The second possibility is that to implement the constructor, use the global / static method, for example, as follows, and you can change the implementation of this method either through some configuration file, or by linking (possibly dynamic binding) with different versions of this method:

 Car::Car() { m_engine = Engine::create(); } 
+1
source

I would say that I allow (through a constructor or property) the ability to add an engine implementation to the car (which is preferably IEngine).

Tests on the machine do not have to worry about what the Engine does if it responds correctly to the results of calls in the Engine. Then use a fake engine to check so you can control the signals sent to the car and you should be good to go.

0
source

All Articles