Databases Reference
In-Depth Information
used. As you recall from Chapter 2, “Entity Framework,” a
TransactionScope
groups
multiple data access operations in a single database transaction. If its
Complete
method is
called before the
TransactionScope
object is disposed, all changes are committed to the
database. However, if the
TransactionScope
object is disposed without calling
Complete
,
all changes are rolled back. This test method takes advantage of this behavior and wraps
all database changes in an anonymous
TransactionScope
, which is always rolled back to
ensure that no junk data was left in the database by the previous test runs.
It is important to ensure that tests can run repeatedly and independently of each other in
order to be effective quality improvement measures. If tests report false errors because data
they expect to be in the database is missing or was changed by other tests, developers will
stop running them and eventually stop maintaining them. Do not assume that any test
data is already available in the database. If you are testing the Order entity, do not assume
that particular Customer or Product entities are readily available. Instead,
create
them in
your test and let the
TransactionScope
rollback the changes at the end of the test. It is
fine to rely on seed data that must be available in any valid database for your application
and implemented in your database deployment script; so, if you have a table that contains
all 50 U.S. states your application uses to verify address information, you can probably
assume that Florida is there:
Testing Validation of Different Proper ties
Testing validation logic of different properties presents another challenge—how do you
distinguish a
ValidationException
thrown by one property from another? The
ExpectedExceptionAttribute
simply asserts that an exception of a certain type is thrown
but cannot distinguish an exception thrown for the
UnitPrice
property from an excep-
tion thrown for the
ProductName
property. To verify validation exceptions down to the
property level, you could modify the test, catch the validation exceptions, and examine
the member names explicitly:
[TestMethod]
public void UnitPrice_IsRequired()
{
using (new TransactionScope())
using (var context = new NorthwindEntities())
{
var product = new Product();
product.UnitPrice = null;
context.Products.AddObject(product);
try
{
context.SaveChanges();
Assert.Fail();
}
catch (ValidationException e)
{
Assert.IsNotNull(e.ValidationResult.MemberNames);