Slashdot is powered by your submissions, so send in your scoop

 



Forgot your password?
typodupeerror
×
Image

The Art of Unit Testing 98

FrazzledDad writes "'We let the tests we wrote do more harm than good.' That snippet from the preface of Roy Osherove's The Art of Unit Testing with Examples in .NET (AOUT hereafter) is the wrap up of a frank description of a failed project Osherove was part of. The goal of AOUT is teaching you great approaches to unit testing so you won't run into similar failures on your own projects." Keep reading for the rest of FrazzledDad's review.
The Art of Unit Testing with Examples in .NET
author Roy Osherove
pages 296
publisher Manning
rating 9/10
reviewer FrazzledDad
ISBN 1933988274
summary Soup-to-nuts unit testing with examples in .NET
AOUT is a well-written, concise book walking readers through many different aspects of unit testing. Osherove's book has something for all readers, regardless of their experience with unit testing. While the book's primary focus is .NET, the concepts apply to many different platforms, and Osherove also covers a few Java tools as well.

Osherove has a long history of advocating testing in the .NET space. He's blogged about it extensively, speaks at many international conferences, and leads a large number of Agile and testing classes. He's also the chief architect at TypeMock, an isolation framework that's a tool you may make use of in your testing efforts – and he's very up front about his involvement with that tool when discussing isolation techniques in the book. He does a very good job of not pushing his specific tool and also covers several others, leaving me feeling there wasn't any bias toward his product whatsoever.

AOUT does a number of different things really, really well. First off, it focuses solely on unit testing. Early on Osherove lays out the differences between unit and integration tests, but he quickly moves past that and stays with unit tests the rest of the book. Secondly, Osherove avoids pushing any particular methodology (Test Driven Development, Behavior Driven Development, etc.) and just stays on critical concepts around unit testing.

I particularly appreciated that latter point. While I'm a proponent of *DD, it was nice to read through the book without having to filter out any particular dogma biases. I think that mindset makes this book much more approachable and useful to a broader audience – dive in to unit testing and learn the fundamentals before moving on to the next step.

I also enjoyed that Osherove carries one example project through the entire book. He takes readers through a journey as he builds a log analyzer and uses that application to drive discussion of specific testing techniques. There are other examples used in the book, but they're all specific to certain situations; the brunt of his discussion remains on the one project which helps keep readers focused in the concepts Osherove's laying out.

The book's first two chapters are the obligatory introduction to unit testing frameworks and concepts. Osherove quickly moves through discussions of "good" unit tests, offers up a few paragraphs on TDD, and lays out a few bits around unit test frameworks in general. After that he's straight in to his "Core Techniques" section where he discusses stubs, mocks, and isolation frameworks. The third part, "The Test Code" covers hierarchies and pillars of good testing. The book finishes with "Design and Process" which hits on getting testing solidly integrated into your organization, plus has a great section on trying to deal with testing legacy systems. There are a couple handy appendices covering design issues and tooling.

Osherove uses his "Core Techniques" section to clearly lay out the differences between stubs and mocks, plus he covers using isolation frameworks such as Rhino.Mocks or TypeMock to assist with implementing these concepts. I enjoyed reading this section because too many folks confuse the concepts of stubbing and mocking. They're not interchangeable, and Osherove does a great job emphasizing where you should use stubs and mocks to deal with dependencies and interactions, respectively.

The walkthrough of splitting out a dependency and using a stub is a perfect example of why this book's so valuable: Osherove clearly steps through pulling the dependency out to an interface, then shows you different methods of using a stub for testing via injection by constructors, properties, or method parameters. He's also very clear about the drawbacks of each approach, something I find critical in any design-related discussion – let me know what things might cause me grief later on!

While the discussion on mocking, stubbing, and isolation was informative and well-written, I got the most out of chapters 6 ("Test hierarchies and organization") and 7 ("The pillars of good tests"). The hierarchy discussion in particular caused me to re-think how I've been organizing an evolving suite of Selenium-based UI tests. I was already making use of DRY and refactoring out common functionality into factory and helper methods; however, Osherove's discussion led to me re-evaluating the overall structure, resulting in some careful use of base class and inheritance. His concrete examples of building out a usable test API for your environment also changed how I was handling namespaces and general naming.

If you're in an organization that's new to testing, or if you're trying to deal with getting testing around legacy software, then the last two chapters of the book are must-read sections. Changing cultures inside organizations is never easy, and Osherove shows a number of different tools you can use when trying to drive the adoption of testing in your organizations. My own experience has shown you'll need to use combinations of many of these including finding champions, getting management buy off, and most importantly learning how to deal with the folks who become roadblocks.

The Art of Unit Testing does a lot of things really well. I didn't feel the book did anything poorly, and I happily include it in my list of top software engineering/craftsmanship books I've read. All software developers, regardless of their experience with unit testing, stand to learn something from it.

You can purchase The Art of Unit Testing with Examples in .NET from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.

*

This discussion has been archived. No new comments can be posted.

The Art of Unit Testing

Comments Filter:
  • xUnit Test Patterns (Score:5, Informative)

    by Nasarius ( 593729 ) on Wednesday February 10, 2010 @03:47PM (#31089842)
    For anyone familiar with the basics of unit testing but struggling to implement it in real world scenarios, I'd strongly recommend xUnit Test Patterns: Refactoring Test Code by Gerard Meszaros.

    The idea is not only that automated testing is good, but that testable code is fundamentally better because it needs to be loosely coupled. I still struggle to follow TDD in many scenarios, especially where I'm closely interacting with system APIs, but just reading xUnit Test Patterns has given me tons of ideas that improved my code.
  • by msclrhd ( 1211086 ) on Wednesday February 10, 2010 @04:35PM (#31090314)

    Kevlin Henny makes the following distinction:

    1. A unit test is a test that can fail if (a) the code under test is wrong, or (b) the test itself is wrong.

    2. An integration test is a test that can fail if (a) the code under test is wrong, (b) the test itself is wrong, or (c) the system environment has changed (e.g. the user does not have permission to write a file to a specific folder).

    John Lakos refers to individual things under test as components. In his model, there are layers of components that build on each other and interact with each other, but these are well-defined components that just happen to depend on other components.

  • by Lunix Nutcase ( 1092239 ) on Wednesday February 10, 2010 @04:47PM (#31090426)

    It's like a car built out of LEGO, sure you can take any piece off and attach it anywhere else, but the problems are not with the individual pieces, but how you put them together.. and you aren't testing that if you're only doing unit testing.

    And that's why you do integration testing too.

  • by msclrhd ( 1211086 ) on Wednesday February 10, 2010 @04:55PM (#31090522)

    When testing a system, if you cannot put a given component under test (or do so by "faking" its dependants -- e.g. by the things that talk to the database) then the architecture is wrong.

    I strive never to have any "fake" parts of the system in a test. It makes it harder to maintain (e.g. changing some of the real components will break the tests). You cannot easily change the data you are testing with, or having a method generate an error for a specific test. You are also not really testing the proper code; not all of it, at any rate.

    You should implement interfaces at the interface boundaries, and have it so that the code under test can be given different implementations of that interface. This means that you don't need to fake any part of your codebase -- you are testing it with different data and/or interface behaviours (e.g. exceptions) that are designed to exercise the code under test. The code under test should not need modification in order to run (aside from re-architecturing the system to make it testable).

    The main goal of testing is to have the maximum coverage of the code possible to ensure that any changes to the code don't change expected behaviour or cause bugs. Ideally, when a bug is found in manual testing, it should be possible to add a test case for that bug so that it can be verified and so that future work will not re-introduce that bug.

    Start where you can. If you have a large project, put the code that you are working on under test first to verify the existing behaviour. This also works as an exploratory phase for code that you don't fully understand.

    Also remember that tests should form part of the documentation. They are useful for verifying an interface contract (does a method accept a null string when the contract says it does? does the foo object always exist like the document says it does?)

  • by lena_10326 ( 1100441 ) on Wednesday February 10, 2010 @05:05PM (#31090678) Homepage

    Unit tests should be trivial for the majority of classes. Good OO design will cause your many of your classes to be single purpose and simplistic therefore the unit tests will also be simplistic. That's the point of OOD (or even modular design)--breaking down complex problems into many simpler problems*.

    Maybe you should consider that unit testing is not just for validating the current set of objects but also validating that future revisions do not break compatibility. In other words it makes regression testing possible or easier with automation.

    Writing the unit tests also serve to prove to your teammates you've thought about boundary conditions and logic errors. When you're forced to think them in a structured way then you're in a better position to catch code bugs while writing the unit tests. Many times you'll find them before even executing the test code.

    Note: If anyone responds with something along the lines of "complex problems cannot always be simplified" I will literally punch you--repeatedly.

"A car is just a big purse on wheels." -- Johanna Reynolds

Working...