What is the best way to test BL (repositories, services etc), which uses some data?
Example: goods/orders. I need to test calculation of discount sum. So I need some goods, the order with collection of goods.

Should I write class to provide fake data (but how can
I use fetching in such case?) or use test database with fake data,
and run all tests in one transaction with rollback at the end?
Should I use mocks (but I can't use mocks for DO Entities)?

I know, that this question isn't about DO supporting, but I think your experience will help all developers to better understand how to do unit testing with DO :)

All our testing is based on NUnit. Nearly all our test fixtures inherit from AutoBuildTest. This type ensures its Domain property is provided for each test (use [SetUp] or [TestFixtureSetUp] to implement this; we use the second option, but do nothing, if Domain property is already set), and allows to change its configuration by overriding BuildConfiguration member (normally we register a specific namespace with specific model there).

By default Domain is built in Recreate mode, i.e. an empty one; you can override Setup method to fill the database with data specific to a particular test. Likely, in your case you should invoke one of external data population services (classes) from this method to fill the initial data - I'd separate this logic from test because many tests tend to share the same initial data, also, data population code is normally written as in tree-like fashion (CreateCustomers, CreateOrders, ...), so it's a good idea to implement each scenario in separate class.

In addition, this class uses environment variables to modify the provided configuration in accordance with a set of rules, since we must run all the test on build server on each backend (i.e. database) and in a set of different mapping scenarios (we use IModule feature to change inheritance mapping and few other options). But likely, you won't need this.

Any test does the following:

Creates a Session

Runs the test itself

Rolls back all the modifications - usually, by rolling back the transaction.

If there is a sequence of transactions, we cleanup all the changes by one of the following ways:

Manually, if this is easy

Automatically - by invoking a special method that rebuilds the Domain (if changes are complex)

In some cases this isn't necessary at all - i.e. if changes shouldn't affect on other tests.

To speedup testing, you can run some tests on memory provider. But remember that currently it can't rollback any changes and can't run the transactions concurrently. Also, it's a bad idea to use it in tests with complex queries on large volumes of data: our query optimizer is pretty simple, so such tests may run faster on SQL Server.

Since some tests are RDBMS-specific, we use a special Require class to skip execution of test on some backends and configurations - e.g. Require.ProviderIs(StorageProvider.Sql) call ensures test will run only on SQL databases. Such methods throw IgnoreException (for NUnit) in case the condition is violated. Again, probably you won't need this, but that's the idea you can use as well.

And few things I'd recommend you to avoid:

Using a real database (e.g. backup) instead of data population routines - people used to dealing other ORM tools (or with plain SQL) frequently make this mistake. In this case you'll need to care about upgrade on each model change instead of thinking about this only closer to release. Refactoring in VS.NET (esp. with ReSharper) helps to change data population routine in accordance with model changes with nearly zero efforts, but data upgrades can be much more complex. Also, you should track versions of such backups, distribute among developers and build servers, ensure changes made by tests aren't left there, and likely, even store them in repository. Obviously, that's a hell. On the other hand, none of such problems appear, if you deal just with C# code.

Developing tests dependent on the order of their execution. I know, that's a normal practice, but sometimes people ignore it. The problem appears when you're using different test runners - e.g. TeamCity, ReSharper and NUnit GUI execute tests in different order.

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)!