How do you test your business objects?
Asked Answered
S

8

6

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?

Spacecraft answered 14/2, 2009 at 3:9 Comment(1)
Found some good rules of thumb here msdn.microsoft.com/en-us/library/ms379625(VS.80).aspx. Agrees with a lot of what everyone is saying.Spacecraft
E
8

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.

Exaggeration answered 14/2, 2009 at 4:20 Comment(2)
Thanks! What are some DB testing frameworks? Or is this something you build yourself?Spacecraft
No, the point is to use an existing framework. I use DBUnit, dbunit.org , but there are others. Just google for "unit testing database".Exaggeration
P
5

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.

Perak answered 14/2, 2009 at 4:17 Comment(1)
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.Spacecraft
A
2

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.

Acetone answered 14/2, 2009 at 4:25 Comment(1)
Thanks! I am using CSLA as my application framework, which doesn't seem to DI friendly. I would love to do this!Spacecraft
C
2

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

Also this question might be interesting.

Classmate answered 6/6, 2009 at 19:37 Comment(0)
E
1

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.

Elenoraelenore answered 14/2, 2009 at 3:28 Comment(0)
S
1

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.

Separatist answered 14/2, 2009 at 4:38 Comment(0)
B
1

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.

Bedstraw answered 14/2, 2009 at 9:37 Comment(0)
H
0

(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.

Hollington answered 24/2, 2009 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.