views:

335

answers:

7

Hi I've read in blogs that the database should not be hit when the unit tests run. I understand the theory, however say i have complex store procedures that are part of a business domain operation. I want to write a set of unit tests for the code related to the business operation, however if i mock the database i have the feeling that im not "really" testing all the parts that are part of the operation. For example someone could create a bug in one of the database code and the tests will still be running ok.

I would like to know if this guideline about unit tests is good in practice. I've seen the concept of "integration tests" however im not sure about what tools to use to do integration tests. For example ¿Is it ok to create an integration test using a test framework like Nunit?

Thanks

Hugo

+1  A: 

The problem in adressing the database in your tests is that a change in the database or a change in your code can fail the test. A unit test normally should point as direct as possible to the change that made him fail. So if you want to test the code for the DB access maybe use a fixed test database. In this way you are sure that the code that accesses the DB is wrong because you know the database hasn't changed and if you want to change the DB setup change the test DB first and see your test fail then fix him and then change the not test DB. In a project I worked in we created a small database that was generated into memory prior to each test.

Janusz
A: 

"...the database should not be hit when the unit tests run..." - unless you're unit testing persistence objects, of course.

I don't know which blogs you're citing, but I'll bet what they're saying is that mocking some components during integration testing can have benefits. If you've already unit tested the persistence tier, there's no need to test it again. The benefit of mocking in that case has more to do with reducing dependencies and uncertainty. For example, you might have unit tested your code, packaged it up, and now it's time to move it into an environment that's closer to production. If the databases you need can't be available (e.g., don't have the proper version of the schema, missing data that you need, or simply needed by another application that got there first), you can use mocks to allow your integration test to proceed without delay.

duffymo
+3  A: 

There are two main reasons for unit tests not hiting the database:

  • You want your tests to go as fast as possible
  • You want to test your code as a single unit, not how it integrates with other code/ database.

In your case you need to test the stored procedures. Then you need to write a test that runs those stored procedures. Either you can run them via your code (Integration test) or you can run them directly from the test (sort of a unit test). In both cases you can use Nunit.

Shiraz Bhaiji
A: 

Well, the thing is, if you have your unittests hit the database, you're not testing just the single unit of code, but instead you're hitting several - also the DAL, stored procedures, etc. Thats why TDD proponents say not to hit the database in unittests.

Its also why you shouldnt hold much weight in pure, TDD-conceptualized, theoretical holy Unit Tests. While unittesting is not a bad thing per se, and in fact is quite important to ensure the programmers build each component properly - system testing is way more important. Overall, it may be harder to find the exact method that caused system tests to fail, they're more realistic and actually test the system.
So-called "Component Testing" - which is more like system testing, but for only one small part of the system, end-to-end - seems to me to be a good compromise.

(Cue the TDD rebuttals now... :) )

AviD
+8  A: 

You are simply in a semantic grey area.

  • System tests cover the whole system from end-to-end.
  • Unit tests can be used to describe a sub-segment of the end-to-end cycle.

In that case your unit tests of your application code would/might not hit the database, but you would/might have unit tests that covered your database stored procedures...

Basically divide your application into things to be tested along partitions that make sense. If you choose the wrong partition line you end up with a big code maintenance problem with mock objects and test scaffolding and stuff...

A common way with web apps is to write a series of unit tests that test the data access layer...

Then write a series of unit tests that test the application layer (including the data layer) ...

And finally write some browser-based system tests...

The trick is to only put information in and out of the middle set - the application layer - through the API and not burrow into the database to see if something worked. That way your tests won't break if you change the data schema.

But sometimes (as I actually currently doing as I write this) you HAVE to look into the database to make a meaningful and robust test suite (I am testing server-server transfer protocols).

Focus on the way that gets maximum code coverage and stability for your application, whilst writing the least amount of testing scaffolding, and avoiding brittleness in your test suite.

Gordon Guthrie
I can't tell you how many times I've said almost the exact same thing. TO OUR Q/A GROUP!!! They see one big test and sometimes don't understand that there are dependencies. I've had some get bent out of shape that they can't add the same record more than once. Then I have to convince them that they need setup and teardown portions added to their tests. (How DARE a lowly programmer/designer tell them how to write tests <G>)
Brad Bruce
A: 

After writing Should one test internal implementation, or only test public behaviour? and discussing people's answers, I think that the answer may depend on how many people are on the development team.

Advantages of testing with the database:

  • Testing is more realistic (using the actual database)
  • Less testing code to write (don't need to write a mock of the database)

Disadvantages of testing with the database:

  • Your tests can't run until the database access layer is written
  • If there's a bug or test failure, you don't know whether the bug is in your code or in the database access layer

The disadvantages are especially important if (but perhaps only if) the person writing the upper layer isn't the same as the person writig the database access layer.

ChrisW
+1  A: 

YMHO There is a bit of semantic issue and a bit of a technical issue here.

A unit test is supposed to test a small part of code, in isolation, to check it without other code. A failed Unit Test should imply that only a small part of code will have to be inspected corrected (tipically, the code implementing the functionality and the unit test itself).

Other scopes of testing exist to check functionality of the system as a whole (system test), or functional tests to validate complete features, or integration tests to check interactions, regression testing to check for the absence of already corrected test etc.

A testing strategy has to be devised for each project, but in general having different categories helps a lot. So unit tests should be restricted to testing the smallest possible units of code, and use other testing procedure to test functionality, integration etc.

The semantic part is whether is correct to use a unit test library to perform some functional test, I guess it is no biggy if you keep your suites separated the strict unit tests and the functional tests (even if they share the testing tool)

FCo