简体   繁体   中英

Integration testing EF5 (or EF4x)

After reading several questions/answers about unit testing Entity Framework, I have decided to forgo unit testing for integration testing. I am going in with the philosophy that interacting with the EF context is a "private" action, because it does not need to be unit tested independently of my service, and can't easily & accurately be mocked.

Note: In my example, I'm using EF5.

First, I have a service method for creating a user:

void CreateUser(string username, string password);

My test assembly has a SetUpFixture (one-time for test run) that creates of my database (EF Code First) and test data:

[SetUpFixture]
public class SetUpFixture
{
    [SetUp]
    public void SetUp()
    {
        using (var context = new MyDbContext())
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());

            // Set up a bunch of initial data and commit
        }
    }
}

Then before each test, my TestFixtureSetup method runs that creates an instance of my DB context, which is set to rollback when it's disposed (after each test), and also creates the instance of my service:

[TestFixtureSetUp]
public virtual void TestFixtureSetUp()
{
    _context = new MyContext(rollbackOnDispose: true);
    UserService = new SignupService(_context);
}

[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
    Context.Dispose();
}

Finally, my actual integration test to make sure that what valid data is passed in, a record with my username got created (and here's where my problem lies):

[Test]
public void ValidDataShouldResultInNewRecordWithUsername()
{
    SignupService.CreateUser("myuser", "fakepassword");

    var q = from user in Context.Users 
            where user.Username == "myuser"
            select user;

    var actualUser = q.Single();

    Assert.AreEqual("myuser", actualUser.Username);
}

Here are my questions:

1) First of all, is this even the way to go testing services dependent on EF? I know there are several approaches, I just want to make sure there's nothing crazy with this approach.

2) Second, how should I verify the service method (CreateUser) did what it was supposed to do, before the data is committed (which I don't want it to commit, so that my database state remains as it was initialized prior to each test)? The query in the test above returns no data, since it wasn't committed yet.

For #2, if you are using SQL Server, you can use Snapshots . You create a snapshot when your test data has been loaded. Then, you run your test, and in the teardown (or whatever post test method you use), you revert to the snapshot. Reverting to a snapshot is very fast, so it is a practical way to test the DB.

There is another approach which I have used to some success. Instead of using a SQL database, use a SQLCE database. Then you can manage your test data as files - you are creating the database anyway. I like the snapshot approach better, but they both work.

For #1, this is an integration test. Hitting the database is exactly the right thing to do, as you are testing the data portion of the application. Abstracting out a repository buys you nothing but more complexity, as then you need to test the repository against the database.

Good luck, Erick

This is close to how all my automated tests are (I don't unit test either, only integration test against a real db). There are two main things I do differently.

The first is I setup a transactionscope in my setup and dispose it in my tear down, without committing. This allows me to query for updated data w But be able to revert the database for the next test. The downside is that you probably can't use transactionscopes in your service layer as I don't know how well nested transactions work.

The other thing I do is trigger a full database rebuild at startup by calling the EF initialize class (I don't have my code in front of me ATM). This way I'm garanteed to have a fresh database from seed data at the beginning of the test run, and it also let's me know if my entity structure is bad,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM