views:

1505

answers:

8

I am wanting to implement automated testing, using the Microsoft testing framework in Visual Studio, for my software development projects. I have created some tests, and all in all, it's pretty easy to use.

What are some better practices for testing business objects, more specifically ones that read and write to a database.

Is it best to setup a separate test database, from the development database, where the user interface is tested from, and just test against that database? Basically just filling it with junk data.

Is it better to embrace some type of clean-up after yourself mentality, meaning, if I am testing the AddUser method, do I add the User, check my tests, and then delete the User?

Do you test each of the CRUD methods in a single test method?

Lastly, what about the individual business rules like verifying strings are of the correct size, start dates are less than end dates, the CustomerId is a correct Customer and so on.

I realize this is a pretty broad question ... just looking for some direction ... taking baby steps.

More information...

Lot's of good answers! I'm not sure I would be able to pull off a mock database. I am using CSLA as the framework for my objects. It would take some serious refactoring to make this testable with mock objects. I'm going to look into this. Though, at some point, I do want to test the database interaction ... when using a mock database, where/when would you actually test the database communication?

One other question ... is it best to keep each test method non-dependent on other tests?

+1  A: 

Generally I create the BO, save it to the db in the fixture setup, then have tests for various insert/update/selects then in my teardown delete the object from the database. It keeps things nice and clean especially when lots of constraints are involved, your test db can get messy real quick if you don't remove everything you create in your tests.

Element
+5  A: 

I would recommend implementing your business objects so that they are unaware of the database. Use methods on the data access layer that can save/retrieve business objects properly depending on their type (i.e., it has an internal mapping between the tables and the objects they correspond to). When testing your business object itself, then you need not worry about the database at all. Simply create the object, perhaps use reflection to set private fields, and conduct your test on the object.

When testing code that needs to interact with the data access layer, use mocking to create a mock data layer and set up expectations on it to return the desired objects or respond properly to saves. You may need to develop your data layer to an interface (or wrap it with a mockable class if using a rigid framework that doesn't support mocking directly). Most mocking frameworks require that methods be virtual to allow a mock implementation to be created. Using interfaces forces the methods in the implementing class to be virtual so mocking is much easier.

tvanfosson
Thanks! This sounds good, but sounds like a lot of work. I am using the CSLA framework for my business objects, not sure how exactly this would translate.
mattruma
+6  A: 

Ideally, you would have business objects that do not directly access the database, but use helper objects or some kind of ORM (Object-relational mapping) framework. Then you can test your BOs without a database, possibly mocking some helper objects. That is probably the cleanest way, because you avoid the complexity of a real DB, and really only test your business logic.

If you cannot avoid combining business rules and DB access into one class (probably a problematic design, but sometimes hard to avoid), then you have to test against a DB.

There pretty much the only reasonable option is to have a separate DB for automatic testing. Your test methods should delete everything on setup on setup, then load all their data, do the test and verify results.

Don't even think about trying initialise the DB once and then run all tests on the same data. One test will accidentally change data, and other tests will mysteriously fail. I've done that and regretted it... Each test really must stand on its own.

To do all this, I strongly recommend some kind of DB testing framework. These help you to clean the DB, load necessary data, and compare query results to expected results. I use DBUnit (for Java), but there are many others for other languages.

sleske
Thanks! What are some DB testing frameworks? Or is this something you build yourself?
mattruma
No, the point is to use an existing framework. I use DBUnit, http://www.dbunit.org , but there are others. Just google for "unit testing database".
sleske
+1  A: 

Use dependency injection. Implement your database methods in an interface. Then write a new implementation of the interface with control data to test the applicable scenarios.

Chuck Conway
Thanks! I am using CSLA as my application framework, which doesn't seem to DI friendly. I would love to do this!
mattruma
+1  A: 

To test DB Access Layer, you should not run all tests on same db. Some tests may fail because they depend on the results of other test. So this is not what you want. Actually after every test, you should return the db status to the original status before the test runs.

In my practice, I keep the test data set in a XML and before every test, it setup the data in db using the XML. So every test runs against some dataset.

Ken Yao
+1  A: 

I support the once saying that you should test you business objects with a moched database. In some cases you might want to have your data persisted as part of the test though. The drawbacks to this are longer running tests and the need for cleanup.

One solution to this that might help you is to use an in-memory database for your tests. SQLite for instance lets you create in-memory databases on the fly, and when you dispose them they are gone. This makes your tests much faster, and you don't have to set up cleanup code - while you actually get to test your SQL / db code through automated tests.

Torbjørn
A: 

(I know you don´t use Java but the general strategy below does not depend on Java at all)

I'm working on a Java project that uses a lot of EJB3/JPA code. I decided to create a kind of mock container able to "deploy" EJBs and use an in-memory database (HSQL) with hibernate entity manager.

This "container" starts up in less than 1 second and allows me to test most business components, including those that access the database via JPA. If a service is, for example, too complex to support then I simply use EasyMock (or any other mock library) to create a fake service and plug in into the "container".

It's been a huge success so far, but required me a couple of days to implement the mock infrastructure.

Antonio
+1  A: 

More info about TDD with CSLA can be found in the answers to this question. Especially this one.

Also this question might be interesting.

fretje