views:

50

answers:

1

I'm trying to write test cases for my web services in a way that I can rollback any database changes they may make. I can try to surround them with a transaction scope, but how do I specify a context for the transaction? In other words, how does the transaction know which database and server to rollback on? In my case, the SQL server runs locally as well as the web services. Before you tell me to call the web services directly without a client, please understand that the web services have very specific runtime environment settings that would be a royal pain to reproduce for my test cases. Perhaps, the transaction scope isn't what I want to use, is there an alternative? Is there a database function I could call to start a transaction? Thanks.

+2  A: 

First you are not doing unit testing. Unit test is about testing single small unit of code (function). When you test a function you are creating unit test for each execution path so that you have full coverage of tested code. But your system under tests includes client to service communication and service to database communication = several tiers of code + configuration. That is called integration testing.

The problem here is how did you design your service? Does your service flow transactions? Transaction flow allows starting transaction at your client and pass it to the service (distributed transaction). It is not default behavior and it requires special configuration of WCF bindings. If you use this approach you can do the same in your test. Start transaction at test and rollback the transaction at the end of the test. If you didn't design service to flow transaction you simply can't use it because your transaction started in the test will not affect the service. In that case you have several choices:

  • Create manual compensation. At the end of each test run custom SQL to move data to initial state. This simulates rollback. I don't recommend this approach.
  • Recreate database at the beginning of each test. This is slow but fully acceptable because integration tests are usually run only on build server few times per day.
  • Don't test WCF service level. WCF service should be only some wrapper on the top of business logic or data access logic. So don't test service level but instead test the wrapped layer. You can probably use transactions there. This approach can be well combined with previous one so that you have some small set of complex integration tests which requires database recreation and some bigger set of tests which can do rollback and use the same database.
Ladislav Mrnka
Thanks. The real problem here is that I don't control the context in which the business layer operates. It's calling a third-party DAL which needs to run under ASP.NET and also checks for licensing info. I can't divorce the two. The test would have to run under IIS in order to work.
Than second approach is probably the best for you.
Ladislav Mrnka
The answer above is correct, but i would add that one should use Mocks to enable the unit tests, this way you can build a suite of Unit and Integration tests easily off the same code base
MetalLemon
Yeah, the problem with mocks is that it becomes lots of code and you have to precisely emulate the thing you're mocking.