I am writing unit tests in .NET that are heavily dependent on database. Unit test modify the data in the database and I want to revert the database to the initial state. I am planning to follow the approach listed below for reverting the database to pre unit-test state.
Approach: I want to create a database snapshot before running each unit test and rollback database to that snapshot after it is finished.
The problem: many users can simultaneously run the test cases. This can result in different snapshots (inconsistent). How can I handle the concurrency problem? I do not want to pollute the database in any way for the sake of running test cases.
I am using SQL Server 2012 and .NET (C#) for accessing the database.
Related
I need to write integration tests for my layer that exposes methods of service. But I need my database to be in a certain state for the tests to pass
For example for testing the GetStoreByID method, I need to have store 1 in my database but not store 2 (for the ko test)
The database is developed and deployed by a another team using a sql project (dacpac)
I use Entity Framework 6.1.3 with an Edmx
What is the best way, in this case, to setup the data in database before tests ?
This link https://msdn.microsoft.com/en-us/library/dn314431(v=vs.113).aspx gives the Microsoft MSDN article on how to write tests using EF6 by faking out the database.
In summary the article covers the subject 'When writing tests for your application it is often desirable to avoid hitting the database. Entity Framework allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data.'
If your data access is separated by an interface (i.e. using something like IDBSet for each of the types), personally I'd avoid depending on the database completely where possible, and use either a fakedbsets (if you need to test repository/DAL code) or just mocking with moq or nsubstitute if you don't.
I know this doesn't specifically answer your question, but the best way to setup test data is do it in memory in my experience with as few external dependencies as possible. The database adds extra moving parts that you don't really want to have to depend on in unit/integration tests. This also adds complexities if you have a CI server etc... that you generally want to avoid.
I have written a .Net application which has many components, some of those components are database access layers which abstract from the rest of the components where the data comes from.
I have unit tested the rest of the components by mocking the database access layer. One way I have of testing the database access layers is to use create new empty databases on the test servers. This can be slow, and most would argue that it is not a unit tests as I depend on the database server.
What I think I want, is a mocked database which I can use to test my database access layer. The mocked database can be given a schema and process SQL commands as if it were a remote database, but in fact it is all in-memory. Does this exists? Or how else can I test my SQL and database <-> data model code.
To solve my problem you may want to know I am using SQL Server, versions 2008 and later, and my code is written in C#, running with .Net 4.5 and using Visual Studio 2013
Note: I do not want to use Linq2SQL/EntityFramework to replace my database access layer, as in my experience it results difficult to debug issues and performance problems.
I tried to phrase my question carefully to avoid people lecturing me on their beliefs in what should be tested and how, but perhaps to be a little more blunt:
I want to unit test my SQL, small changes to that have a big impact on the outcome of the program. I do have integration tests, but it takes much longer to create a release for the test environment than it does to tweak code and run the unit tests.
I appreciate people taking the time to read my question and respond anyhow.
I don't know if it's going to be the best answer, but. The way we're doing is that we're using SQLite, which is an in-memory database. There are a number of different ways to set it up, we use NHibernate as an ORM, and for that it is fairly easy to set up using FluentNHibernate, but I don't think it's much harder using any other framework either:
Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => ... )
.BuildConfiguration()
.BuildSessionFactory();
I think you can run queries against a SQLite database without any ORMs as well, e.g. using the base SqlConnection class.
This database can accept migrations, schemas, etc. It behaves very close to a proper MsSql database, we can run any DDL an DML statements against it, and it works fine. Since it's all in-memory, it's also pretty fast.
With domain-driven design is best to make tiny steps (change design or code, unit testing ...).
I think that is good (to make the script=to write the code) of SQL Server from SQL Server Management Studio, but with DDD the database code is written at the end, after we tested the design.
With code written in c# and then create database with EF you will change the c# code frequently, and that implicitly will change database code a lot.
How best to proceed?
Assuming you are working on a brownfield project. Then for a given user story:
1) Design and unit test your domain model.
2) Then integration-test your infrastructure. This includes testing repository implementations against database that gets created dynamically for these tests (can be in-memory or embedded). NHibernate generates schema for you automatically, not sure about EF.
Being persistence-agnostic definitely helps here because you can test against SQLite but run against SQL Server for example.
3) Then manually write migration scripts for your production database. There is no black magic that will help you with this step. The script can later be executed by a framework like RoundhousE. More information here.
Rinse and repeat. For a green field project that is not deployed yet, you can skip step 3) and generated 'baseline' script on first production deployment.
DDD preaches persistence ignorance, which states that your domain artifacts (classes for entities, value objects) should be unaware of how they're persisted. However, technical persistence concerns cannot always be easily avoided or delayed. As a result, the model in code will usually be affected by constraints of the persistence technology.
You've already foreshadowed the best approach: tiny steps. The question is what constitutes a step. Initial steps can consist of the designing the model in code and then implementing persistence. A subsequent step repeats the process. The fact that the steps are small reduces the chance that you'll create a design in code which cannot be easily persisted all while prioritizing focus on the model over the database.
Regarding the use of SQL Management studio vs EF generators, this is a matter of preference. I prefer to hand-code SQL, others may enjoy the generation facilities of EF.
I am writing integration tests to verify the behaviour in my repositories. The problem I run into is that I want to start with a clean database for every test. I managed to do so by writing the SetUp as follows:
[SetUp]
public void SetUp()
{
_applicationContext = new TestApplicationContext();
_applicationContext.Database.Connection.Close();
_applicationContext.Database.Delete();
_applicationContext.Database.Create();
_tenantRepository = new TenantRepository(_applicationContext);
_userRepository = new UserRepository(_applicationContext);
}
The TestApplicationContext sets the database name to TestDatabase.
This works fine until I want to check the actual database for the result of my test. Then I make a connection from MSSQL server to the same database, which won't close until I either:
shut down MSSQL server
delete the database with the option "close all connections"
The only way I found is via SQL commands. Maybe it's because of my n00b knowledge regarding MSSQL, but I was kinda hoping for a "close connection" button / option.
How can I close the connection to the database from MSSQL server?
Or, is there a way I can do this programmatically from C#?
UPDATE:
Maybe I wasn't very clear. But the test SetUp fails after I opened MSSQL and viewed the contents of a table. This is because MSSQL also creates a connection to the TestDatabase, and my integration test is not able to close that connection. So I am looking for a solution that allows me to close the connection I created from MSSQL server.
You can work around the connection problem if instead of dropping and re-creating whole database you just drop and re-create selected (or all tables).
You could create little script that will do it for you in a way that you do not need to hard-code table names:
http://www.apexure.com/blog/2010/07/29/delete-all-tables-in-sql-server-database/
Alternatively, Julia Lerman in her book "Programming Entity Framework: Code First" mentiones this approach in more mature form, as incorporated as a custom database initializer:
As well as writing your own custom initializers, you can also find
initializers that other people have created. One example of this is
available in the EFCodeFirst.CreateTablesOnly NuGet package. This
initializer will allow you to drop and create the tables in an
existing database, rather than dropping and creating the actual
database itself. This is particularly useful if you are targeting a
hosted database where you don’t have permission to drop or create the
entire database.
You're releasing the connection back to the connection pool, not actually closing it. Instead of creating/deleting the database for each test, begin new transaction in setup and rollback in cleanup. This way no changes will be committed to your database and your test will always start from a clean state.
Also, because you are testing against live database, I wouldn't call your tests "unit" tests. Unit tests do not have any external dependencies.
The only way to reliably get an exclusive lock on a database is to use the SINGLE_USER WITH ROLLBACK IMMEDIATE technique. I recommend that you create a database snapshot with an empty state and restore to that snapshot each time. That will be much faster.
I am still having a issue getting over a small issue when it comes to TDD.
I need a method that will get a certain record set of filtered data from the data layer (linq2SQL). Please note that i am using the linq generated classes from that are generated from the DBML. Now the problem is that i want to write a test for this.
do i:
a) first insert the records in the test and then execute the method and test the results
b) use data that might be in the database. Not to keen on this logic cause it could cause things to break.
c) what ever you suggest?
You should choose option a).
A unit test should be repeatable and has to be fully under your control. So for the test to be meaningful it is absolutely necessary that the test itself prepares the data for its execution - only this way you can rely on the test outcome.
Use a testdatabase and clean it each time you run the tests. Or you might try to create a mock object.
When I run tests using a database, I usually use an in-memory SQLite database.
Using an in memory db generally makes the tests quicker.
Also it is easy to maintain, because the database is "gone" after you close the connection to it.
In the test setup, I set up the db connection and I create the database schema.
In the test, I insert the data needed by the test. (your option a))
In the test teardown, I close the connection to the db.
I used this approach successfully for my NHibernate applications (howto 1 | howto 2 + nice summary), but I'm not that familiar with Linq2SQL.
Some pointers on running SQLite and Linq2SQL are on SO (link 1 | link 2).
Some people argue that a test using a database isn't a unit test. Regardless, I belief that there are situations where you want automated testing using a database:
You can have an architecture / design, where the database is hard to mock out, for instance when using an ActiveRecord pattern, or when you're using Linq2SQL (although there is an interesting solution in one of the comments to Peter's answer)
You want to run integration tests, with the complete system of application and database
What I have done in the past:
Start a transaction
Delete all data from all the tables in the database
Setup the reference data all your tests need
Setup the test data you need in database tables
Run your test
Abort the transaction
This works well provided your database does not have much data in it, otherwise it is slow. So you will wish to use a test database. If you have a test database that is well controlled, you could just run the test in the transaction without the need to delete all data first.
Try to design your system, so you get mock the data access layer for most of your tests. It is valid (and often useful) to unit test database code, however the unit tests for your other code should not need to touch the database.
You should consider if you would get more benefits from “end to end” system tests, with unit tests only for your “logic” code. This depend to an large extent on other factors within the project.