21

During TDD training based on medical software case we are implementing the following story: "When user presses Save button, system should add patient, add device and add device data records".

The final implementation will look something like this:

if (_importDialog.Show() == ImportDialogResult.SaveButtonIsPressed)
{
   AddPatient();
   AddDevice();
   AddDeviceDataRecords();
}

We have two ways to implement it:

  1. Three tests where each verifies one method (AddPatient, AddDevice, AddDeviceDataRecords) was called
  2. One test which verifies all three methods were called

In the first case if something wrong is happend to if clause condition, all three tests will fail. But in the second case if test fails, we are not sure what is exactly wrong. What way would you prefer.

0

5 Answers 5

9

But in the second case if test fails, we are not sure what is exactly wrong.

I think that would largely depend on how good error messages the test produces. In general, there are different ways to verify that a method has been called; e.g. if you use a mock object, it will give you a precise error message describing which expected method was not called during the test. If you verify that the method was called via sensing the effects of the call, it is up to you to produce a descriptive error message.

In practice, the choice between options 1 and 2 also depends on the situation. If I see the code you show above in a legacy project, I choose the pragmatic approach of Case #2 just to verify that each of the 3 methods are called properly when the condition is fulfilled. If I am developing this piece of code right now, the 3 method calls would most likely be added one by one, at separate points in time (possibly days or months away from each other), so I would add a new, separate unit test to verify each call.

Note also, that either way, you should also have separate unit tests to verify that each of the individual methods do what it is supposed to do.

2
  • Won't you find it reasonable to eventually combine those three tests into one? Sep 23, 2011 at 14:14
  • @Idsa, can be a reasonable decision, although in practice I rarely bother with this kind of refactoring. Then again, I am working with legacy code, where the priorities are different: we focus on increasing the test coverage of existing code, and keeping the growing amount of unit tests maintainable. Sep 25, 2011 at 13:27
35

The Granularity in your example seems to be the difference between unit- and acceptance tests.

A unittest tests a single unit of functionality, with as few dependencies as possible. In your case, there could 4 unittests

  • does AddPatient add a patient (i.e. calls the relevant database functions)?
  • does AddDevice add a device?
  • does AddDeviceDataRecords add the records?
  • does the unamend main function in your example call AddPatient, AddDevice and AddDeviceFunctions

Unittests are for the developers, so they get confidence, that their code is technically correct

The acceptance tests should test the combined functionality, from the perspective of the user. They should be modeled along the user stories, and be as high level as possible. So, you don't have to check if functions are called, but if a benefit visible to the user is achieved:

when the user enters the data, clicks ok and...

  • ...goes to the patient list, he should see a new patient with the given name
  • ...goes to the device list, he should see a new device
  • ...goes to the new device's details, he should see new datarecords

acceptance tests are for the customers, or, for building a better communication with them.

To answer your question "what would you prefer": what is a bigger problem to you right now, bugs and regression (=> more unittests) or understanding and formalizing the big picture (=> more acceptance tests)

0
13

We have two ways to implement it:

That's false.

Three tests where each verifies one method (AddPatient, AddDevice, AddDeviceDataRecords) was called

You must do this to be sure it works.

One test which verifies all three methods were called

You must also do this to be sure the API works.

The class -- as a unit -- must be completely tested. Each method.

You can start with a test that covers all three methods, but it doesn't tell you much.

if test fails, we are not sure what is exactly wrong.

Correct. That's why you test all methods.

You must test the public interface. Since this class does three plus one things (even if they're bundled in one method because of user story) you must test all four things. Three low-level and one bundle.

3

We write our unit tests for meaningful sentences of functionality which many times map to a method (if you've written your code well), but sometimes get bigger, encompassing many methods.

For example, imagine that adding a patient to your system needs some subroutines (child functions) to be called:

  1. VerifyPatientQualification
  2. EnsureDoctorExistence
  3. CheckInsuranceHistory
  4. EnsureEmptyBed

We might also write unit test for each of these functions.

2

One simple rule of thumb that I've been following is to name the test so that it describes precisely what the test does. If the name of the test gets too complex it is a sign that the test is perhaps doing too much. So for example naming a test to do what you propose in option 2 may look like PatientIsAddedDeviceIsAddedAndDeviceDataRecordsWhenSaved which is much more complex than three separate tests PatientIsAddedWhenSaved, DeviceIsAddedWhenSaved, DataRecordsWhenSaved. I also think the lessons that can be learned from BDD are pretty interesting where each test is really representative of a single requirement that could be described in a natural language. In this vein I like the idea of handing a list of the test names to a non-developer for verification that we have covered all necessary requirements so anytime a single test becomes too intimidating in terms verbosity I think it's a great reason to consider breaking up the tests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.