When the unit test requires the CRUD (Create, Retrieve, Update, Delete) operation on the database, a large amount of repeated junk data will be left in our database after the test, these spam are confusing, aren't they? In addition, some errors may occur due to the garbage in our next test.
So how should we deal with the junk data and ensure the stability of the test? Obviously, we need to keep the database in the same state before and after each test. In other words, we need "undo" to perform CRUD operations on the database in the test.
How did you perform this "undo" operation before? Is it possible to manually remove or use ADO. NET for transaction processing? These methods are all feasible, but they are not good enough for us. Because they all require us to write more code, which affects our development efficiency.
Now, let's start with the focus of this Article. We can use the automatic transaction processing function of COM + to help us implement our "undo ".
First, write a base class that automatically rolls back the database operations after each method is completed:
Using System;
Using NUnit. Framework;
Using System. EnterpriseServices;
Namespace TransactionTest
{
[TestFixture]
[Transaction (TransactionOption. Required)]
Public class DatabaseFixture: ServicedComponent
{
[TearDown]
Public void TransactionTearDown ()
{
If (ContextUtil. IsInTransaction)
{
ContextUtil. SetAbort ();
}
}
}
}
Next we will write another example program using this base class: using System;
Using NUnit. Framework;
Using System. Data;
Using System. Data. SqlClient;
Namespace TransactionTest
{
Public class CategoryTests: DatabaseFixture
{
String CONN = @ "Server = 192.168.0.58 \ sun; Database = Northwind; uid = Account; pwd = password ";
[Test]
Public void InsertTest ()
{
String categoryName = Insert ("Test category ");
VerifyRowExists (categoryName, true );
}
[Test]
Public void DeleteTest ()
{
String categoryName = Insert ("Test category ");
Delete (categoryName );
VerifyRowExists (categoryName, false );
}
/** // <Summary>
/// Add a record
/// </Summary>
/// <Param name = "categoryName"> </param>
/// <Returns> </returns>
Private string Insert (string categoryName)
{
Using (SqlConnection conn = new SqlConnection (CONN ))
{
String strSQL = "Insert Categories (CategoryName) values ('" + categoryName + "')";
SqlCommand cmd = new SqlCommand (strSQL, conn );
Conn. Open ();
Cmd. ExecuteNonQuery ();
}
Return categoryName;
}
/** // <Summary>
/// Delete a record
/// </Summary>
/// <Param name = "categoryName"> </param>
/// <Returns> </returns>
Private string Delete (string categoryName)
{
Using (SqlConnection conn = new SqlConnection (CONN ))
{
String strSQL = "Delete from Categories Where CategoryName = '" + categoryName + "'";
SqlCommand cmd = new SqlCommand (strSQL, conn );
Conn. Open ();
Cmd. ExecuteNonQuery ();
}
Return categoryName;
}
/** // <Summary>
/// Verify the executed database operations
/// </Summary>
/// <Param name = "categoryName"> </param>
/// <Param name = "shouldExist"> </param>
Private void VerifyRowExists (string categoryName, bool shouldExist)
{
SqlConnection conn = new SqlConnection (CONN );
Conn. Open ();
String strSQL = "Select * from Categories where CategoryName = '" + categoryName + "'";
SqlCommand cmd = new SqlCommand (strSQL, conn );
SqlDataReader dr = cmd. ExecuteReader (CommandBehavior. CloseConnection );
Assert. AreEqual (shouldExist, dr. HasRows );
Dr. Close ();
}
}
}
If you compile the above program, you also need to add a strong name to the program, otherwise it will fail
Use sn-k test. snk in the command line
Copy test. snk to the program directory, and then set
[Assembly: AssemblyKeyFile (@ "... \ .. \ test. snk")]
Original article: http://weblogs.asp.net/rosherove/articles/dbunittesting.aspx