In my unit tests, I want to provide complete isolation between tests. Thus, any entities created in one test method should not exist in another test method.

For performance reasons, it would be ideal to be able to create one domain before any tests are executed (i.e. in a class decorated by SetUpFixture attribute... or, in your "AutoBuildTest" example, in the TestFixtureSetUp method).

I tried to create an outer transaction inside my test methods and rollback the transaction at the end of the test. The problem with this approach is that business rules are not enforced within the test method. For example, if I create a unique index on MyEntity.Name property, then I should not be able to create 2 instances of MyEntity with the same Name value. Unfortunately, using this approach, I can violate this rule, and an exception is never thrown.

Is there a suggested approach? I think isolation is absolutely critical in order to be able to write proper unit tests.


Updated at 18.02.2010 22:32:12

Obviously, creating a domain for each test method is not an option (even using in-memory storage, because each domain build process takes a few seconds).

I should be able to create one domain that is shared between all tests. Any changes made in a test method should be validated (validation aspects, onvalidate method, index uniqueness constraints, etc.). Then, at the completion of the test, these changes should be rolled back to provide isolation for the next test method.


Updated at 19.02.2010 0:10:34

Alex,

Here's what I'm doing... similar to the AutoBuildTest you guys provide in your DO4 project templates.

AutoBuildTest class <-- all test fixtures inherit from this class

TestFixtureSetUp method: Build a domain TestFxitureTearDown method: dispose of domain SetUp method: A) open session B) open "isolation" transaction scope TearDown method: A) rollback "isolation" transaction scope B) dispose session

SomeTest class <-- inherits from AutoBuildTest class

SomeTestMethod1: a) open nested transaction scope with TransactionOpenMode.New, b) create/modify entities, c) make asserts, d) commit nested transaction via transactionScope.Complete()


OK, so what I was doing actually does work. I had just forgotten to apply one of the nUnit attributes to a setup method.

I don't use Session.Persist(). Do you think I need to?

Thank you!

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Feb 18 '10 at 22:29

ara's gravatar image

ara
395868791


One Answer:

A bunch of advices:

  1. Using TestFixtureSetUp / TestFixtureTierDown is recommended approach.

  2. Use Session.Persist to flush all the changes (simulate commit).

  3. If there are validation rules, ensure all InconsistentRegions are closed (see Validation.Disable() method), or call Validation.Enforce() to enforce processing of all delayed checks.

  4. Use nested transactions inside the test, if necessary (Transaction.Open(TransactionMode.New)).


> OK, so what I was doing actually does work. I had just forgotten to apply one of the nUnit attributes to a setup method. I don't use Session.Persist(). Do you think I need to?

No, you shouldn't - I forgot that Session.Persist is inevitably called on nested transaction commit (as well as on its opening). If this isn't done, we're moving a part of operations that are considered as performed inside it to outer transaction, which is absolutely incorrect.

answered Feb 18 '10 at 23:59

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA