2

I m actually studying Unit testing, reading some articles on the internet and trying to understand how it works exactly, but it's not very clear for me actually.

What should I test ?

I have seen that it's a good thing to create interfaces and make our testable classes implement this interface (permitting to implement it in our test classes) but what are exactly the classes that I should test ?

For example, admitting that I have a project structure like this :

  • Presentation Layer (MVC)
  • Business Layer (Service / Repositories)
  • DB Layer (Mongo, Mysql etc..)

Should I only test services and repositories ? Should I create an interface to all my classes, even if I have only one implementation of it (two with the test) ?

What does my test really return ?

I have read an article, in which the author explaning the way to test a DB access using mocks :

  • There is a class "S" which is a business service implementing an interface "I", that manage the data taken from the db to provide business objects
  • There is a class "C" which is a controller and has a renderView method, which send to the view an array of the business objects given by the service "S".

1/ In the first test, he tests the value returned by "S" on getBusinessObject only using a collection of String. So he only tests if he has data in the collection (null, the content after adding an item etc...)

2/ In the second test, he mocks the "S" service to use it to test the renderView and only tests if he gets 2 results when the mock object method returns 2 objects.

My question is, how can we say that the test is a representation of the real state of our programm ?

I mean, it's possible that we have to make a difficult job in a service, with condition, iteration etc...

I dont really understand the impact of making unit tests if we mock a class that

return "a string"; 

comparing to a classe that transform drastically a String in the method.

Maybe I didn't understand the aim of unit testing in fact.

gnat
  • 20,543
  • 29
  • 115
  • 306
mfrachet
  • 1,561
  • 3
  • 15
  • 23

2 Answers2

10

I've had contractors who have left after creating a database layer with a set of unit tests which passed, but didn't actually save anything to the database so everything was lost if you restarted the system.

So test the parts of your system you want to work by writing tests which compare the expected behaviour with the real behaviour.

If those parts are small enough to be tested without much scaffolding and configuration, then those tests are unit tests. If they require multiple parts to work in concert, then they are integration tests.

If you find that you'd rather be coding than waiting for long integration tests to run, then refactor the system into smaller pieces which can be tested using unit tests.

Often this involves creating interfaces and mocks/stubs so the business and UI layers can be tested quickly without a real database. The UI layer probably doesn't care whether the thing being displayed is 'a string' or real data. Similarly, the DB layer may not care whether it is being asked to store real data or 'a string'†. The business layer which does something to the data may well care.

The key here is that the mocks should return something which will exercise the functionality under test, but are no more complicated than is necessary to do that.

You end up with more unit tests and fewer integration tests and a better factored system, but you still need the integration tests to check it actually does fulfil the overall spec.

† actually, most of my projects store quantities of time series data so the nature of the real data dictates the design of the database, so generally I test using a few months real data, not made-up data.

Pete Kirkham
  • 2,041
3

Unit tests are essentially tests of a single component. With perhaps some mock objects to fake some interfaces used by the module.

You are testing that for a given input you receive the expected output. If you test involves other modules components or services which cannot be mocked then it is no longer a unit test.

As such they are very useful. You can test edge conditions and extreme values which are unlikely but could possibly appear in real data.

However unit testing is only the beginning. The module needs to be tested with the other modules in the system, and, with any other system that it interacts with.

In addition you need to do realistic tests with real users a program can only be considered to be "working" if the end user thinks it works.