views:

141

answers:

4
+6  Q: 

How to unit test?

Basically I have two main questions:

  • What exactly should you unit test?
  • How do you do it?

The problem is I have several applications that rely in a database connection and/or are communication applications, which mean most of the test cases are integration tests (or so I think).

Most classes are fairly simple by themselves, but the ones that implement the communication protocol, which are the ones that would be useful to automate the testing, can seem to fit well into the "unit test" model.

Another example. I developed I pipe structure with multithreaded support for a consumer/producer pattern. When a thread reads the pipe and finds it empty it blocks until a writer writes into the pipe. Should I use unit tests to test that class?

How do you decide what to unit test?

Edit: I mean writing unit tests for automated unit testing.

A: 

Unit testing is testing the entire unit works the same as it did before the change, with the improvements made in the change.. If you are making a change to a window of a module, then you test the module. This is in comparison to a system test, which is to test every module. If your change affects many modules (not sure how your system is set up), then it should get a system test.

glasnt
Hmmm, my fault, I meant automated unit test... like the one you actually code :)
Jorge Córdoba
+3  A: 

You Unit tests units of your code. The real question is what exactly makes up a unit?

In an object oriented environment a unit is a class. A class because behaviours of an object vary with the state of the object, so testing a method in isolation will not yeild the most complete results.

First you need to identify the invariants of the class. That is, the things that will always be true for all instances ofthe class. E.g. in a Fraction class an invariant may be denominator != 0.

Next you need to identify the contracts of each method, that is, the pre and post conditions of the methods.

Then you write tests for each condition that may arise. So for a single class you may end up with many test methods to test the various conditions that each method could encounter. At each test you ensure that the invariants of the class holds and the contract of the method is never broken.

In some cases like the example that you provided it may be necessary to create other objects in the environment in order to test the conditions of your class. In those instances you may use mock objects.

Vincent Ramdhanie
So even if you need to mock other objects or simulate external events or devices it can be considered a unit test and a test shall be written for it?
Jorge Córdoba
@Jorge Corboda Yes. I think so. Many environments like code that runs in a container are hard to unit test by itself. So creating mock objects for the test is considered good practice. It is important that the test code can run independently though.
Vincent Ramdhanie
Although technically, any test of code that has a dependency outside the unit being tested (database, file system, etc.) is an integration test. However, the two terms can be, and often are, used interchangeably.
ZombieSheep
+1  A: 

You should abstract your infrastructure concerns (ie code that retrieves data from your database, code that does file i/o, etc) so that you can stub/mock those parts in order to unit test your application. And then you will be able to write targeted/specific tests against your infrastructure code to test that out.

You will be finding yourself creating more interfaces (to create seems within your application), and needing to use better OO principles (ie. SOLID) in order to develop an application that is more testable.

I was in the same boat a year ago that you were in. And the one book that really helped me through it (along with some hands on practice) is The Art of Unit Testing by Roy Osherove

Jon Erickson
I've heard good things about that one...
RSolberg
+1  A: 

Unit tests test units (that is method or function) in isolation, in a dedicated, controlled environment. Each unit test creates in own environment by instantiating only the classes needed to execute one test, putting them in a known state, then it invokes the method to be tested and verify the outcome. This verification is done by assertions on the behavior of the method (as opposed to its implementation).

Performing the verification on the behavior and not on the implementation is important as this allows modifying the implementation without breaking the unit tests, and therefore using the unit tests as a safety net for the modification.

All language have [at least] one unit test framework whose role is to execute the unit tests. There are two ways to write unit tests: test-first or test-last.

Test-first is also called Test-Driven Development. Basically it takes three steps:

  1. write a failing test
  2. write just enought code to make it pass
  3. refactor the code to clean it up (remove duplication ...)

Proponents of TDD claim that this leads to testable code, while it could be hard to write unit tests after the fact, especially when methods do several things. It is recommended to follow the Single Responsibility Principle.

Regarding the pipe structure and communications protocol example, some guidelines say that a test is not a unit test if:

  • It talks to the database
  • It communicates across the network
  • It touches the file system
  • ...

When a thread reads the pipe and finds it empty it blocks until a writer writes into the pipe. Should I use unit tests to test that class?

I would test the class, but not the blocking read method, as I presume it is build from a blocking call to the read() function of the Operating System.

philippe
There's a *very* important step 4 to TDD - "Ensure the tests still pass after refactoring". Obvious, but sometimes overlooked.
ZombieSheep
Agreed it's important - but it is part of Refactoring, not TDD. TDD cycle is "red, green, refactor".
philippe