views:

72

answers:

1

Continuing another but similar question about testing (see here). I'll use a similare example (pseudocode)

class LinkDisplayer
    method constructor(LinkStorage)
    method displayLatestLinksByCategory(number_of_them)

class LinkStorage
    method saveLink(Link)
    method retrieveLatestLinksByCategory(category, number_of_them)

class Link
    method getUrl()
    method getDescription()
    method getCategory()

So the linkDisplayer uses the LinkStorage to get Link(s). The behavior I want to test is 'shouldDisplayLatestLinks'. In my test, do I need to mock LinkStorage, and let it return mocked Link objects with mocked getUrl() etc behavior?

Testing 'leaf' classes is easy enough but I still find it very difficult to find my way in testing the other ones.

+2  A: 

Short Answer:

You should be mocking/stubbing anything that is not under the direct control of your SUT. Only test the behavior of your SUT, and never write a test that attempts to confirm behavior that is outside that scope (ie. testing mocks/stubs).


Long Answer:

it can be difficult to see the forest for the trees. When you are the one who wrote all the code you can find it difficult sometimes to steer clear of testing too granular of an implementation detail.

You have the right idea with wanting to test behavior, and rightly so red flags went off when you started thinking about your test. This is exactly what TDD is all about, as it helps to expose design flaws. Just remember though, only test the behavior of the SUT. Everything else should be under the control of your unit test (mocks), otherwise it would not be a unit test.

Put yourself in the position of the consumer of the LinkDisplayer class, and ask yourself "How would I use this in production code?" You would probably just call the method and expect that it worked. You most certainly would not make a call to the database to ensure that it did in fact retrieve the correct number of elements, or that they were sorted by category would you? So why attempt to write a test for that.

What should the end result be of calling displayLatestLinksByCategory?

I see two possible answers to that question based on your sample, and what actions you should take based on those answers:

  1. Get some stuff from the database using a specific method, and display it somewhere.
    • If this is what that method does, then those are the only two things you should be testing for. Mainly, that the right method was called on the data access component with the right arguments; and that the data returned got to where it needed to go.
    • What you should not be testing is the shape*** of the data returned as this would only be testing behavior that your test is already in complete control over. It would be like testing that a variable you just set to true in your test is in fact true.
  2. Get some stuff from the database using a specific method and return it
    • At this point red flags should be going off all over the place. If this is the only thing that this method is good for, then you have to ask yourself why you would not just call the data access method directly? As the consumer of this class you already have control over which data access component is being used (you provided it) so why have a middle man.

* It is ok to test how your SUT responds to specifically shaped data. You might want to throw an exeption if null is returned, or the collection is empty. You might want to clip extra values from the list if more than N were returned, but you never want to test something that is outside the behavior of your SUT. Because you are in direct control over how the data being returned from you mocks is shaped, testing that would lead to the worst kind of test possible; a test that doesn't test anything, but still passes.

Josh