tomashkerr | 16 Dec 2011 11:44
Picon
Favicon

how big unit tests should be

I'm writing some pet-project code to practice my TDD skills and have one doubt according to tests size and complexity.

Let's say I need to implement a class that fetches data from external system (say DB), then formats specific
response using this data and writes the response via external interface.

I think of using mock objects here. I suppose I need db access service mock, response formatter mock and
external interface mock.

Now is it ok to write first test exercising all that stuff at once? I mean (pseudocode):

testExecute():
   // prepare
   expect(dbMock).toCall(fetch).andReturn(result)
   expect(formatterMock).toCall(format).with(result).andReturn(formattedResponse)
   expect(externalApiMock).toCall(send).with(formattedResponse)

   // act
   myComponent.execute()

   // exercise
   // nothing here

Or should I write separate tests for each call or incrementally add mock calls to this one?

Now suppose I need to log message and return specific empty response if something is wrong with data load.
How should I name this test? I think of "testReturnEmptyResponseAndWriteLogOnException".
But as the names contains "and" it seems that this test does too much.
Again should I separate testing response and logging separately?

I'd be grateful if you could point me to right direction here
(Continue reading)

Lior Friedman | 16 Dec 2011 14:50
Picon

Re: how big unit tests should be

Hi,
Generally speaking your test should be big enough to test one thing and one
thing only.
If you get a feeling your test is too big, listen to that feeling.
Any chnce it is telling you that your class is too big?

Btw in most cases, when you have an "and" in your test name its a hint that
you should have more tests. Each one shoul verify one aspect of the action

Hope this helps
Lior
On Dec 16, 2011 3:41 PM, "tomashkerr" <tomashkerr <at> yahoo.com> wrote:

> **
>
>
> I'm writing some pet-project code to practice my TDD skills and have one
> doubt according to tests size and complexity.
>
> Let's say I need to implement a class that fetches data from external
> system (say DB), then formats specific response using this data and writes
> the response via external interface.
>
> I think of using mock objects here. I suppose I need db access service
> mock, response formatter mock and external interface mock.
>
> Now is it ok to write first test exercising all that stuff at once? I mean
> (pseudocode):
>
> testExecute():
(Continue reading)

Sam Serpoosh | 16 Dec 2011 14:55
Picon
Gravatar

Re: how big unit tests should be

Hi tomashkerr,

the most important thing that you should be careful about in TDD and in
general unit-testing, is that
it should cover "ONE UNIT OF WORK" and nothing more and nothing less. in
the first scenario you are
obviously doing more than one unit. in the first glance it seems of three
units of work (maybe it's more
that's why I said first glance:D) one unit is for database data transfer,
another is for formatting the data
and the third one is about showing the right thing in your interface. you
should test them separately and then test interaction between them.
the test you've described is more like an integration test for these three
units and can be a good Acceptance Test for a specific functionality of
your project.

and for the second scenario as you've mentioned yourself first you should
test logging and empty response separately
and make sure that each of them works perfectly and after that write
another test for their interaction. because when you do
this baby step style you're focusing to a little area and if your tests
fails you know where is the problem. in this case when the logging
 test fails then you know you should check the logging not anything else.
but if you test both of them at once when it fails you have at least
three things to check: 1) logging 2) empty response 3) interaction between
them.

Hope it helps. Good Luck ;)

--

-- 
(Continue reading)

Steven Smith | 16 Dec 2011 15:49
Picon
Gravatar

Re: how big unit tests should be

I got the impression that he's testing the controller/orchestrator of the 3
separate dependencies, which he's already broken out into separate classes
(GOOD).  So, the main unit tests he's looking at, for the unit of the
controller/orchestrator, are that it calls its dependencies when everything
works (happy path), and that it handles error conditions appropriately (sad
paths), including any logging, return codes, and/or thrown exceptions that
it does.  Anyway, I do think he's testing a single unit of work here.

Steve

On Fri, Dec 16, 2011 at 8:55 AM, Sam Serpoosh <ssjesus287 <at> gmail.com> wrote:

> **
>
>
> Hi tomashkerr,
>
> the most important thing that you should be careful about in TDD and in
> general unit-testing, is that
> it should cover "ONE UNIT OF WORK" and nothing more and nothing less. in
> the first scenario you are
> obviously doing more than one unit. in the first glance it seems of three
> units of work (maybe it's more
> that's why I said first glance:D) one unit is for database data transfer,
> another is for formatting the data
> and the third one is about showing the right thing in your interface. you
> should test them separately and then test interaction between them.
> the test you've described is more like an integration test for these three
> units and can be a good Acceptance Test for a specific functionality of
> your project.
(Continue reading)

Steven Gordon | 16 Dec 2011 16:35
Picon

Re: how big unit tests should be

Not only should a good TDD test test a single unit of work, it should
test a single characteristic of that work.  Otherwise, I do not see
how it made sense to write the test before writing just a small amount
of the code.  With this test, if you wrote it first, you would have to
write a whole bunch of the code, possibly in multiple classes, to make
it pass.

Perhaps, as an additional unit test *after completing TDD*, this test
might not be too big.

A good rule of thumb is whether or not you can easily come up with a
single good name for the test that fully describes what it is testing
and distinguishes it from your other tests.  The name "testExecute()"
is a good sign that something is wrong with this test.

SteveG

------------------------------------

Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/testdrivendevelopment/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/testdrivendevelopment/join
    (Yahoo! ID required)
(Continue reading)

Rick Mugridge | 16 Dec 2011 21:31
Picon

Re: how big unit tests should be

I basically agree with your approach. It appears that your class-under-test
is coordinating the actions of other objects to carry out a unit of work.
It's appropriate to mock those other objects (as interface roles) and TDD
out the coordination role code. I'd often do that before I'd write the
implementation of those other objects/roles.

After the good path, TDDing the bad paths makes sense. A bad path will have
to mention several things happening, both in terms of causing the problem
and responding to it, so "and" seems appropriate to me. However, the
elements of the "and" are better split between the given, when, and then
parts of the test/specification. Although I don't use a BDD-specific test
framework, I find it most helpful to use that form in all my tests.

So instead of "testReturnEmptyResponseAndWriteLogOnException", I'd use
something like (in a Scala multi-line string):

"""Given a MarketActivityReportCoordinator managing some data formatting
     When the MarketActivityDataSource throws a DataUnavailable exception
     Then the problem details are sent to the SeriousErrorLogger"""

I'm keen to get the naming right in terms of the intent of its activity,
although I'm making it up here. BTW, "Coordinator" in the name above seems
slightly smelly.

I have to disagree with the responses that argue that the focus is too
large. To handle a part of the good path, for example, would mean having to
segment the implementation of the coordinator in an unhelpful way that
doesn't make sense as a specification. Those who needlessly avoid a mocking
approach end up in the position of having to build the other role
implementations first, and then treat this stage as a mini integration
(Continue reading)

Steven Gordon | 16 Dec 2011 22:58
Picon

Re: how big unit tests should be

Maybe I could agree if I saw the preceding tests.

What I often see in the wild is the simplest tests looking like this
one and a bunch of even more complex ones following them.

Keep the tests simple!

On Fri, Dec 16, 2011 at 1:31 PM, Rick Mugridge <rick.mugridge <at> gmail.com> wrote:
> I basically agree with your approach. It appears that your class-under-test
> is coordinating the actions of other objects to carry out a unit of work.
> It's appropriate to mock those other objects (as interface roles) and TDD
> out the coordination role code. I'd often do that before I'd write the
> implementation of those other objects/roles.
>
> After the good path, TDDing the bad paths makes sense. A bad path will have
> to mention several things happening, both in terms of causing the problem
> and responding to it, so "and" seems appropriate to me. However, the
> elements of the "and" are better split between the given, when, and then
> parts of the test/specification. Although I don't use a BDD-specific test
> framework, I find it most helpful to use that form in all my tests.
>
> So instead of "testReturnEmptyResponseAndWriteLogOnException", I'd use
> something like (in a Scala multi-line string):
>
> """Given a MarketActivityReportCoordinator managing some data formatting
>     When the MarketActivityDataSource throws a DataUnavailable exception
>     Then the problem details are sent to the SeriousErrorLogger"""
>
> I'm keen to get the naming right in terms of the intent of its activity,
> although I'm making it up here. BTW, "Coordinator" in the name above seems
(Continue reading)

George Dinwiddie | 17 Dec 2011 19:35
Favicon

Re: how big unit tests should be

Rick,

I haven't been following this discussion, but this caught my eye.

On 12/16/11 3:31 PM, Rick Mugridge wrote:
> I have to disagree with the responses that argue that the focus is too
> large. To handle a part of the good path, for example, would mean having to
> segment the implementation of the coordinator in an unhelpful way that
> doesn't make sense as a specification. Those who needlessly avoid a mocking
> approach end up in the position of having to build the other role
> implementations first, and then treat this stage as a mini integration
> step.

That last sentence seems like a false dichotomy to me.  Certainly I 
don't do much mocking within the system I'm building (preferring to test 
compound objects as a whole), and don't end up in the position you 
describe.  Perhaps I don't understand what you mean by "needlessly avoid."

> "Growing OO Software" is an excellent book on applying TDD, and
> particularly on using mocking in an effective way.

Steve and Nat do excellent work, but that's not the only way to work.

  - George

--

-- 
  ----------------------------------------------------------------------
   * George Dinwiddie *                      http://blog.gdinwiddie.com
   Software Development                    http://www.idiacomputing.com
   Consultant and Coach                    http://www.agilemaryland.org
(Continue reading)

Rick Mugridge | 17 Dec 2011 20:30
Picon

Re: how big unit tests should be

In the end, it's a matter of preference. I read the the original post as
being about how to use a GOOS style. So I was concerned that some replies
were arguing for a change without being clear about the perfectly fine
choice between the GOOS and "state-based" approaches to this particular
coordinator problem.

I find the following. Mocking in the GOOS style encourages an outside-in
approach. Of course, mocking is only needed with coordinators, and that may
only be a small part of the code. Mocking is not used with classes with
local state or with side-effect-free methods.

The "state-based" approach can be:

   - outside-in, with a stack of partial work in progress as you work
   inwards
   - inside-out, where the leaf classes need to be done before those
   classes that use them. Hence my comment, George. And Sam, perhaps you're
   assuming this to be the only approach?

I prefer to TDD in a GOOS style because it works better for me than in the
past when I didn't use mocks. I like working outside-in and not having to
carry partial work. The GOOS style encourages the definition of roles, and
I'm keen for the reduced dependencies that result. Of course, it's possible
to use roles with other approaches, but the tests don't help to drive them
out.

Cheers, Rick

On Sun, Dec 18, 2011 at 7:35 AM, George Dinwiddie
<lists <at> idiacomputing.com>wrote:
(Continue reading)

Adam Sroka | 17 Dec 2011 21:43
Picon
Gravatar

Re: how big unit tests should be

On Sat, Dec 17, 2011 at 11:30 AM, Rick Mugridge <rick.mugridge <at> gmail.com> wrote:
>
> I find the following. Mocking in the GOOS style encourages an outside-in
> approach. Of course, mocking is only needed with coordinators, and that may
> only be a small part of the code. Mocking is not used with classes with
> local state or with side-effect-free methods.
>

Encourages, perhaps, but does not force. It is not that unusual for me to:

1) Test-drive the implementation of the "leaf class"
2) Test-drive the collaborator while dynamically mocking/stubbing the
implementation I already wrote (perhaps extracting an interface if
necessary for the given language.)

This is neither "state-based" nor "outside-in." But, perhaps I am just
strange ;-)

> The "state-based" approach can be:
>
>   - outside-in, with a stack of partial work in progress as you work
>   inwards
>   - inside-out, where the leaf classes need to be done before those
>   classes that use them. Hence my comment, George. And Sam, perhaps you're
>   assuming this to be the only approach?
>
> I prefer to TDD in a GOOS style because it works better for me than in the
> past when I didn't use mocks. I like working outside-in and not having to
> carry partial work. The GOOS style encourages the definition of roles, and
> I'm keen for the reduced dependencies that result. Of course, it's possible
(Continue reading)

Rick Mugridge | 17 Dec 2011 22:04
Picon

Re: how big unit tests should be

Yes, very good point on choosing where to TDD next to gain the most
information, lower risk, etc.

Like you, I choose those points carefully, so am not always working from
the very outside. Eg, last week I dived into building just enough of some
low-level infrastructure (graph database) to convince myself that there
were no unknown risks, before jumping back out to the upper levels of the
app.

Cheers, Rick

On Sun, Dec 18, 2011 at 9:43 AM, Adam Sroka <adam.sroka <at> gmail.com> wrote:

> **
>
>
> On Sat, Dec 17, 2011 at 11:30 AM, Rick Mugridge <rick.mugridge <at> gmail.com>
> wrote:
> >
> > I find the following. Mocking in the GOOS style encourages an outside-in
> > approach. Of course, mocking is only needed with coordinators, and that
> may
> > only be a small part of the code. Mocking is not used with classes with
> > local state or with side-effect-free methods.
> >
>
> Encourages, perhaps, but does not force. It is not that unusual for me to:
>
> 1) Test-drive the implementation of the "leaf class"
> 2) Test-drive the collaborator while dynamically mocking/stubbing the
(Continue reading)

Steven Smith | 16 Dec 2011 15:45
Picon
Gravatar

Re: how big unit tests should be

Hi,

I think you want to keep your tests small, relatively DRY, but most
importantly intent revealing.  One of the key ways to achieve the last
point is through using good names.  The convention I now use, which is
borrowed from BDD-style tests, is to name my test classes for the class I'm
testing and perhaps even a specific method, and end it with Should, and
then complete that sentence with each method.  So in your case if you're
testing the FooComponent's GenerateResponse method, you might do something
like:

public class FooComponentGenerateResponseShould {
  public void ReturnEmptyResponseAndLogErrorOnException()
  public void ReturnSuccessResponseAndLogSuccessGivenValidInputs()
}

Sometimes this style can result in rather long class and test names, which
is good in that they're explicit, but also a smell if you see lots of
AndDoThisOtherThingAndSomethingElse etc. because you're probably violating
Single Responsibility Principle at that point.

When mocking, if I have more than one test method that will use the same
mocked behavior (but not all tests in the class), I'll create a private
method to do the mock setup, and then name this based on the scenario.  For
instance:
private void SetUpMocksForSuccessfulInteractions();

I don't usually have more than one test per failure condition, so I don't
generally have separate mock setup methods for these, but if you do have
several such methods, you could certainly create methods like
(Continue reading)

tomashkerr | 19 Dec 2011 09:37
Picon
Favicon

Re: how big unit tests should be

Hi all.

Lots of really useful opinions here. 
Thanks very much for your time and responses.
One more question I have.

It's true that this is controller's action I'm gonna test. It is also kind of orchestration of 3 different
collaborators. So do I understand it correctly that in ideal TDD world my tests codebase should grow like that:

1) only test if data loading collaborator is called (both happy and different sad paths)

2) exercise only data formatter's calls prividing some sample data (again both happy and sad paths)

3) exercise only response writer with sample data formatted

4) write integration test for all the orchestration

Test 1) is simple. No previous collaborator is required. In tests 2) and 3) is there a need to stub "previous"
collaborators? I mean in 1) should I stub data laoder to return sample data, or just declare sample data
straightforward? And in 3) should I stub loader to return sample data and stub formatter?

It seems that I need to get more practice in TDD and find kind of my own style. Then most of the beginner's
issues will disappear.
I'm reading GOOS right now but can't say I feel comfortable with all that stuff.

--- In testdrivendevelopment <at> yahoogroups.com, Steven Smith <ssmith.lists <at> ...> wrote:
>
> Hi,
> 
> I think you want to keep your tests small, relatively DRY, but most
(Continue reading)


Gmane