views:

31

answers:

1

How do I create a unit test that updates a record into database in asp.net

+1  A: 

While technically we don't call this a 'unit test', but an 'integration test' (as Oded explained), you can do this by using a unit testing framework such as MSTest (part of Visual Studio 2008/2010 professional) or one of the free available unit testing frameworks, such as NUnit.

However, testing an ASP.NET web project is usually pretty hard, especially when you've put all you logic inside web pages. Best thing to do is to extract all your business logic to a separate layer (usually a separate project within your solution) and call that logic from within your web pages. But perhaps you’ve already got this separation, which would be great.

This way you can also call this logic from within your tests. For integration tests, it is best to have a separate test database. A test database must contain a known (and stable) set of data (or be completely empty). Do not use a copy of your production database, because when data changes, your tests might suddenly fail. Also you should make sure that all changes in the database, made by an integration test, should be rolled back. Otherwise, the data in your test database is constantly changing, which could cause your tests to suddenly fail.

I always use the TransactionScope in my integration tests (and never in my production code). This ensures that all data will be rolled back. Here is an example of what such an integration test might look like, while using MSTest:

[TestClass]
public class CustomerMovedCommandTests
{
    // This test test whether the Execute method of the
    // CustomerMovedCommand class in the business layer
    // does the expected changes in the database.
    [TestMethod]
    public void Execute_WithValidAddress_Succeeds()
    {
        using (new TransactionScope())
        {
            // Arrange
            int custId = 100;

            using (var db = new ContextFactory.CreateContext())
            {
                // Insert customer 100 into test database.
                db.Customers.InsertOnSubmit(new Customer()
                {
                    Id = custId, City = "London", Country = "UK"
                });

                db.SubmitChanges();
            }                

            string expectedCity = "New York";
            string expectedCountry = "USA";

            var command = new CustomerMovedCommand();
            command.CustomerId = custId;
            command.NewAddress = new Address()
            {
                City = expectedCity, Country = expectedCountry
            };

            // Act
            command.Execute();

            // Assert
            using (var db = new ContextFactory.CreateContext())
            {
                var c = db.Customers.Single(c => c.Id == custId);

                Assert.AreEqual(expectedCity, c.City);
                Assert.AreEqual(expectedCountry, c.Country);
            }
        } // Dispose rolls back everything.
    }
}

I hope this helps, but next time, please be a little more specific in your question.

Steven
Great explanation. About 'unit test' I will add you can 'mock' your layers. The principle is to simulate, as far as possible, what will happen in real situation to validate your code without doing the real stuff : impacting your data, your files or processes... A data mock will simulate what will be done in your database but will never connect or access the database. I guess it's not what you want to check but its a manner to isolate your data access test (unit test) from your database mapping test (integration test). A mock is generally a 'unit test' because the environment doesn't matter.
JoeBilly
@JoeBilly: I agree. Integration tests should be a last resort and you should try to make the architecture unit test friendly. However, doing this takes a lot of effort (and experience). As a consultant I often advice less experienced teams to start doing integration tests, because I requires less changes to their architecture. And LINQ does seem to make matters worse: You'll never know for sure if your O/RM supports the LINQ query you wrote. Because of this, I love to see a in-memory provider added to the Entity Framework that behaves exactly as the real EF database providers.
Steven