2008. 12. 16. 13:36

Writing unit tests to validate a data access layer (DAL) can be a time consuming (but life saving) task. One of the biggest challanges of DAL unit tests is assuring that you have consistent data to pull from the database. Dedicating a database with static data for unit tests doesn’t always work. As unit tests are added to the project, data may need to be added to the database. This can cause previously created tests to fail, and a lot of time can be lost trying to resync everything.

One technique for getting around the unit test database consistency issue is to write data to the database you expect to find. The steps for doing this would be:

  • Begin a transaction in your unit test.
  • Write the data to the database that your data access layer will need.
  • Test the data access layer functionality against the inserted data.
  • Roll back the transaction.

Using a transaction has a couple of distinct advantages. Since you are running in the scope of an uncommitted transaction, your fellow developers running unit tests will not see your added data (isolation). Also, rolling back the transaction places the database back to the original state in which you found it.

Managing transactions by explicitly attaching them to the connection object doesn’t always work well when testing a data access layer. Since the DAL often contains code to retrieve its own connection, the following sequence often occurs:

  • Begin a transaction in your unit test.
  • Write the data to the database that your data access layer will need.
  • Call the Data Access Layer. The Data Access layer creates its own connection.
  • The DAL attempts to read the new data from the database. It is blocked, though, because it is in a different transaction than the unit test transaction, and will not be able to complete until the DAL commits.

The TransactionScope object helps alleviate this problem. It sits on top of the Distributed Transaction Coordinator, and will assign any code running within its context to the same transaction. In other words, a TransactionScope context within your unit tests will force your data access layer code to run within the same context. Isolation is maintained from other developers, but your DAL can access and manipulate the data as needed. (This does require that you have the Distributed Transaction Coordinator Service running on the box that handles the transaction.)

To demonstrate, let’s assume that I have a DAL method that I want to test that returns all users from a database. This method gets its own connection, retrieves the users, and returns them as a DataSet.

public DataSet GetUsers()
{
DataSet dataSet = new DataSet();
string connectionString = GetConnectionString();

using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = "SELECT * FROM [User]";
SqlCommand command = new SqlCommand(sql, connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(dataSet);
}

return dataSet;
}

Here is the unit test to test this code. It doesn’t test nearly all of the functionality you would want to check in a real unit test, but it does demonstrate the TransactionScope. Note that the TransactionScope object doesn’t have an explicit RollBack() method. The Rollback occurs if the TransactionScope object is disposed without Complete() being called on it. This occurs at the end of the using block.

[TestMethod()]
public void GetUsersTest()
{
string connectionString = GetConnectionString();

using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
connection.Open();
DataLayer dataAccessLayer = new DataLayer();

DataSet dataSet = dataAccessLayer.GetUsers();
AddNewUser("Fred", connection);

dataSet = dataAccessLayer.GetUsers();
DataRow[] dr = dataSet.Tables[0].Select("[UserName] = 'Fred'");
Assert.AreEqual(1, dr.Length);
}
}
}

Hope this is helpful. Good luck and code safe!

MW


[ 출처 : http://dotnetthoughts.wordpress.com/2007/11/10/transactionscope-and-unit-tests/ ]


-----------------------------------------------------


ASP.NET에서 단위 테스트를 진행하던중..

DataSet으로 얻어진 값을 비교하는 방법이 있을지 고민해봤다..

과연.. Assert 클래스로 DataSet의 값을 비교할 수 있을까?

간단하게 테스트해보았지만 역시나 안되었고..

MSDN을 참고해보니 역시 그런건 없어.. Assert 클래스는... 정말 간단한... 젠장..

여기저기 검색을 해보니까 얻어진 DataSet의 길이를 비교하는게 있더군..

역시 얻어진 값을 비교할 수는 없는건가보다..

간접적으로 그 크기(길이)가 같으니 같은 값을 가질것이라고 여기는 방법뿐인가?

물론 값의 일부가 같은지 비교도 가능하지만..

노가다로 전체 값을 다 비교해보던지..후후;

암튼... asp.net에서의 단위테스트의 한계를 점차 느끼고 있다..;;; ㄷㄷ;;


혹시 이 부분에 대해서 조언을 주실분이 계신가요??

Posted by 열라착한앙마

댓글을 달아 주세요