Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Effective transition from unit testing to integration testing

I'm currently investigating how we should perform our testing in an upcoming project. In order to find bugs early in the development process, the developers will write unit tests before the actual code (TDDish). The unit tests will focus, as they should, on the unit (a method in this case) in isolation so dependencies will be mocked etc etc.

Now, I also would like to test these units when they interact with other units and I was thinking that there should be a effective best practice to do this since the unit tests have already been written. My thought is that the unit tests will be reused but the mocked objects will be removed and replaced with real ones. The diffent ideas I have right now is:

  • Use a global flag in each test class that decides if mock objects should be used or not. This approach will require several if statements
  • Use a factory class that either creates a "instanceWithMocks" or "instanceWithoutMocks". This approach might be troublesome for the new developers to use and requires some extra classes
  • Separate the integration tests from the unit tests in different classes. This will however require a lot of redundant code and maintaining the test cases will be twice the work

The way I see it all of these approaches have pros and cons. Which of these would be preferred and why? And is there a better way to effective transition from unit testing to integration testing? Or is this usually done in some other way?

like image 592
John Snow Avatar asked Apr 02 '13 13:04

John Snow


5 Answers

I would go for the third option

  • Seperate the integration tests from the unit tests in different classes. This will however require alot of redundant code and maintaining the test cases will be twice the work

This is because unit tests and integration tests have different purposes. A unit test shows that an individual piece of functionality works in isolation. An integration test shows that different pieces of functionality still work when they interact with each other.

So for a unit test you want to mock things so that you are only testing the one piece of functionality.

For an integration test mock as little as possible.

I would have them in separate projects. What works well at my place is to have a unit test project using NUnit and Moq. This is written TDD as the code is written. The integration tests are Specflow/Selenium and the feature files are written with the help of the product owner in the planning session so we can verify that we are delivering what the owner wants.

This does create extra work in the short term but leads to fewer bugs, easier maintenance, and delivery matching requirements.

like image 152
Andy Nichols Avatar answered Oct 20 '22 14:10

Andy Nichols


I agree to most other answers, that unittesting should be seperate from integrationtesting (option 3).

But i do not agree to your contra arguments:

[...] This (seperating unit from integration testing) will however require a lot of redundant code and maintaining the test cases will be twice the work.

Generating objects with test data can be a lot of work but this can be refactored to test-helper clases aka ObjectMother that can be used from unit and integration testing so there is no need for redundancy there

In unit tests you check different conditions of the class under tests.

For integration testing it is not neccessary to re-check every of these special cases. Instead you check that the components work together.

Example

You may have unit-tests for 4 different situations where an exception is thrown. For the integration it is not neccessary to re-test all 4 conditions One exception-related integration test is enough to verify that the integrated system can handle exceptions.

like image 26
k3b Avatar answered Oct 20 '22 12:10

k3b


An IoC container like Ninject/Autofac/StructureMap may be of use to you here. The unit tests can resolve the system-under-test through the container, and it is simply a matter of registration whether you have mocks or real objects registered. Similar to your factory approach, but the IoC container is the factory. New developers would need a little training to understand, but that's the case with any complex system. The disadvantage to this is that the registration scenarios can become fairly complicated, but it's hard to say for any given system whether they'd be too complicated without trying it out. I suspect this is the reason you haven't found any answers that seem definitive.

like image 21
jlew Avatar answered Oct 20 '22 12:10

jlew


The integration tests should be different classes than your unit tests since you are testing a different behavior. The way that I think of integration tests is that they are the ones that you execute when trying to make sure that everything works together. They would be using inputs to portions of the application and making sure that the expected output is returned.

like image 1
Schleis Avatar answered Oct 20 '22 14:10

Schleis


I think you are messing up the purpose of unit testing and integration testing. Unit testing is for testing a single class - this is low level API. Integration testing is testing how classes cooperate. This is another higher level API. Normally, you can not reuse unit tests in integration testing because they represent different level of system view. Using spring context may help with setting up environment for integration testing.

like image 1
Vitaly Avatar answered Oct 20 '22 13:10

Vitaly