有时数据库里还有一些逻辑,触发器,约束等. 个人十分不建议把业务逻辑放在数据库里实现. 最常见的数据库表的操作create, read, update和delete(简称CRUD)
, 例如我们需要测试某个Add方法,在这个测试方法完成后, 希望这条测试数据清除掉. 这样做是 为了不影响其它的测试方法也访问同一数据库对象.
首先,我们可以使用.net 2.0中提供的TransactionScope类, 下面的代码基于MsTest的单元测试:
1: [TestClass] 2: public class DbTestBase 3: { 4: private TransactionScope scope; 5: 6: [TestInitialize] 7: public void SetUp() 8: { 9: this.scope = new TransactionScope(); 10: } 11: 12: [TestCleanup] 13: public void TearDown() 14: { 15: this.scope.Dispose(); 16: } 17: } |
上面代码我们看到在标记TestInitialize特性SetUp方法中创建TransactionScope的实例,在TestCleanup特性TearDown方法中调用TransactionScope的Dispose方法. 然后我们继承这个测试基类:
1: [TestClass] 2: public class DateBaseTesting : DbTestBase 3: { 4: /// <summary> 5: /// Test Insert record to database 6: /// </summary> 7: /// <seealso cref="http://www.cnblogs.com/wintersun"/> 8: /// <remarks>Any database modification will be roll back</remarks> 9: [TestMethod] 10: public void TestAddWithEmployeeRepository() 11: { 12: //arrange 13: var employee = this.CreateNewEmployee(); 14: var employRepository = RepositoryHelper.GetEmployeeRepository(); 15: 16: //act 17: employRepository.Add(employee); 18: employRepository.Save(); 19: 20: //assert 21: var employeelist = 22: employRepository.Repository.Find(e => e.EmployeeID == employee.EmployeeID); 23: Assert.IsNotNull(employeelist); 24: CollectionAssert.AreEqual(new List<Employee>() { employee }, employeelist.ToList()); 25: } 26: 27: 28: private Employee CreateNewEmployee() 29: { 30: var employee = new Employee 31: { 32: ManagerID = 2, 33: ContactID = 3, 34: Title = "Developer", 35: BirthDate = new DateTime(1965, 1, 1, 0, 0, 0), 36: HireDate = DateTime.Now, 37: Gender = "M", 38: MaritalStatus = "M", 39: ModifiedDate = DateTime.Now, 40: NationalIDNumber = "2", 41: rowguid = new Guid(), 42: CurrentFlag = true, 43: VacationHours = 2, 44: SickLeaveHours = 3, 45: SalariedFlag = false, 46: LoginID = "myworkbase\\peter" 47: }; 48: return employee; 49: } 50: 51: } |
上面的TestAddWithEmployeeRepository中场景是数据访问层基于EntityFramework的Repository模式, 这里的操作是先是创建实体,然后是提交. 实际中可以是您的任何代码块,ADO.NET或其他的数据访问组件. 当我们执行这个单元测试后,这个TransactionScope将被释放. 之前插入的那条记录将被清除.
假设你不想用基类, 只是简单在某个方法中, 可以这样做:
1: [TestMethod] 2: public void TestWrapTransactionScope() 3: { 4: WrapTransactionScope(() => TestAddWithEmployeeRepository()); 5: } 6: 7: /// <summary> 8: /// Wraps the transaction scope for unit testing 9: /// </summary> 10: /// <param name="action">The action method</param> 11: /// <remarks>author http://www.cnblogs.com/wintersun </remarks> 12: public void WrapTransactionScope(Action action) 13: { 14: using (var scope = new TransactionScope()) 15: { 16: action(); 17: } 18: } |