At RIMdev, We are closing in on 7 months of using our Automation libraries to test a WebAPI application. This post will explain some of the best practices we've found to get valuable and fast(ish) tests. Here, in no particular order, is our wisdom learned through the school of hard knocks.
When a unit test works, don't write an integration test.
Sometimes it is easier to write an integration test as compared to a unit test. This is especially true if you use Sandbox. Take the time to slow down and refactor your code to support a unit test.
Understand your bottle necks.
Most of our integration tests depend on SQL Server LocalDb and IIS Express. The creation and seeding of our databases can be expensive. Creating datasets that can be used across tests without shared state is tough, but worth the spin up costs. This becomes even more important with we also have to spin up IIS Express. Logically grouping tests into fixtures can dramatically make tests run faster.
We use XUnit and utilize the
[Collection](https://gist.github.com/bradwilson/8423477) attribute. This can share fixtures across multiple tests.
Automatic test runners are a huge headache with integration tests.
I love NCrunch, but the style of tests we had did not work well with this tool. Imagine creating a database and IIS Express instance on every keystroke; most machines crumble at the thought of such a scenario.
Skip IIS Express and go straight to OWIN
If you can, run your application in memory using OWIN. This bypasses HTTP requests entirely and can speed up your test spin up and tear downs.
Keep your datasets small
It can be tempting to export a production database and have a load script that seeds your test database. Only load as much data as you need to assert your expectations.
Entity Framework cannot be mocked completely
I've written about unit testing Entity Framework in the past, but it becomes nearly impossible to duplicate all EF behavior in memory. It is important to test your EF queries against a real database.
Always refactor your tests
As you grow your integration test suite, you will notice patterns appearing around your tests. Take the time to refactor so that your integration setup slowly moves towards one way of doing things. You'll thank yourself when you hit unexpected behaviors.
Beware the SQL Timeout
If you try to load too much, you will get inevitable timeouts. Make sure you set your
Connection Timeout in addition to your
SqlCommand timeout to appropriate times.
Failures can be more cryptic than your regular unit tests
Failures can be very cryptic when performing integration tests with IIS Express. Build mechanisms into your application that can expose failures outside of the debugger.
Flat read structures can make it easier to unit test
If your application can read from flat data structures, you can bypass the complexity of LINQ to SQL vs. LINQ to Objects. This makes it easier to mock data in memory and bypass integration tests completely. This is where a CQRS pattern can help.
I personally favor unit tests over integration tests, but integration tests can offer more value when SQL Server or IIS Express are involved. Taking into account what we learned can help you build a better integration test suite.