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
  • 21,442
  • 29
  • 112
  • 288
mfrachet
  • 1,481
  • 3
  • 15
  • 21
  • 3
    It's a good question and valid concerns (though I didn't understand the last bit about string transformation), but while I didn't downvote, I flagged it for closing. Why? 1. I feel that it's way too broad (at the very least there's two questions asked at once, each of them deserving a book) 2. It's so basic and generic that it has been already tackled many times on this website. I would suggest that you search for similar questions (and answers) here, read up, and then get back to the subject with more specific doubts, like, perhaps, focusing closer on your mocking example. – Konrad Morawski Dec 19 '14 at 10:00
  • possible duplicate of [What should you test with unit tests?](http://programmers.stackexchange.com/questions/750/what-should-you-test-with-unit-tests) – gnat Dec 19 '14 at 10:21
  • 1
    See also http://programmers.stackexchange.com/questions/212887/rethinking-testing-strategy (Rethinking testing strategy) – Roman Susi Dec 19 '14 at 10:48
  • 2
    `My question is, how can we say that the test is a representation of the real state of our programm?` It's not. Testing can prove the presence of bugs, but not their absence; to *prove* correctness you need to reason about the code instead of pretending it's a black box. You'll never get even remotely close to testing every property of every possible program state, even for pure deterministic code. Unit testing is a sanity check. – Doval Dec 19 '14 at 12:41
  • Additionally, any object that internally relies on interacting with something outside your program (e.g. a database) in a non-trivial way is only partially testable. In order to test the component you'd have to simulate the database, and you'll make the same assumptions about its behavior as you did when writing the code. If your assumptions about the database's behavior are wrong, your mock database will return something different than the real one would, and you don't have unit tests to catch that. So even if the unit test passes, the code will be wrong when run against a real DB. – Doval Dec 19 '14 at 12:48

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
  • 1,798
  • 14
  • 15
  • So unit testing corresponds only to the way of testing output from input and not the actual implementation of the function exactly ? If I have a function in a service that addition something. Should I mock this service ? Testing addition is easy so... Sould I create a mock that do exactly the same thing ? – mfrachet Dec 22 '14 at 07:47
  • 1
    @Skahrz you mock the things you're not testing, so if you want to test the thing which calls the service without having network overhead, then you'd mock the service. But you also unit test the service itself to check that it is working. – Pete Kirkham Dec 22 '14 at 12:52
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.

James Anderson
  • 18,049
  • 1
  • 42
  • 72
  • According to some authors (e.g. http://www.joelonsoftware.com/articles/fog0000000043.html) you also definitely need human testers who thoroughly verify your software. – Giorgio Dec 19 '14 at 12:38