tags:

views:

60

answers:

2

I understand the general idea about unit testing and have used it in scenarios where complex interactions were happening in a system, but I still have a question about all of those principles coming together.

We are cautioned about not testing the framework, or the database. Good UI design does not lend itself to non-human testing. UI interaction in general is excluded in MVC frameworks. In many apps what is left?. 37signals talks about extensive unit testing, but in an app like Basecamp or Backpack, what exactly are the types of things being tested through appropriate unit tests? What would 100% code coverage mean in that scenario?

EDIT: I am not tearing down apps like Backpack - they are awesome, but the work seems to go more into the design and interaction instead of complex logic (in fact, they espouse that very idea). In those areas of that app, where CRUD and the hierarchy of which object is related to which pretty much cover it, is the appropriate amount of unit tests zero? Is the point of tests in that case to be another copy of the validation code (required, regex, etc.)?

+2  A: 

You're testing to ensure that the business logic (in many apps this is the "service" or "logic" layer) matches up with your business users' description of how the business really works. You're testing to make sure that, for instance, just because you add 6% sales tax to all purchases from Pennsylvania, you aren't also giving a bonus 6% credit when you give someone a gift card.

There is (or there should be) a whole lot of brain juice in the layers of the application that stand between the UI and the database. That's the stuff to test the heck out of.

Jim Kiley
+5  A: 

TDD for business apps works like this.

  1. Write down a business requirement.

  2. Write down a test for that requirement.

  3. Write code that passes the test.

The trick is that there are many junky non-business requirements that don't need extensive testing.

  • "saves to a database" isn't a business requirement. It's technical.

  • "activates a button on the GUI for some situation" isn't a business requirement, it's part of the interface.

  • "backup" isn't a business requirement; it's security or business continuity or something.

Consider a concrete example.

Requirement -- "You can't borrow books until you've paid your fines."

Tests.

  1. Attempt to borrow book with fine.

  2. Attempt to borrow book with no fine.

Code.

class FinesNotPaid( unittest.TestCase ):
    def setUp( self ):
        # load some fixtures with users, books and fines outstanding.
    def test_should_not_checkout_book( self ):
        x = TheCheckoutClass()
        x.checkoutBook( someBook )
        self.fail( "Should have thrown error" )

class FinesPaid( unittest.TestCase ):
    def setUp( self ):
        # load some fixtures with users, books and fines paid.
    def test_should_not_checkout_book( self ):
        x = TheCheckoutClass()
        x.checkoutBook( someBook )
        self.success(  )

class NoFines( unittest.TestCase ):
    etc.

These are Business Rules implemented by classes that are separate from your database and your GUI. These are classes in an application domain layer.

Your CRUD rules are business rules. You need to test them. However, you don't need to test every database-related feature. You need a few "can I create and persist an object?" tests. You have to trust that the ORM, the Data Access layer and the Database actually work. You don't write tests to exhaustively test the built-in features of the ORM.

Code coverage (100% or 80% or 10%) is largely meaningless. Is software that has tests with 80% code coverage actually 20% more likely to fail? It doesn't work that way. Testing every line of code doesn't cover every logic path, so stop worrying and start testing.

Test the business use cases. If they pass and there's untested code, then -- perhaps -- you wrote too much code.

S.Lott
It might be splitting hairs, but this might fall under BDD more so than TDD. The end of this post is pretty interesting (http://consultingblogs.emc.com/jamesbroome/archive/2009/10/16/asp-net-mvc-controllers-bdd-the-perfect-match-part-3-the-accountcontroller-contd.aspx)
R0MANARMY
Some folks call it DDD -- Domain Driven Development. There's a lot of needless hair-splitting between BDD, DDD and TDD. I think they created the other terms to make business analysts feel useful.
S.Lott