TA的每日心情 | 慵懒 2018-10-23 14:32 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]测试小兵
|
数据访问层在分层结构,比较常见. 有时可能是数据访问模块. 假设数据访问层后端是数据库,那我们如何测试他们的呢? 有时实际这种测试是集成测试了.
有时数据库里还有一些逻辑,触发器,约束等. 个人十分不建议把业务逻辑放在数据库里实现. 最常见的数据库表的操作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: }
上面的代码演示了, 我们用Action委托实现另一个方法包装一下目标方法使其在TransactionScope块中.
我们还可以使用xUnit 类库 这实现同样的操作, 这里使用是xUnit 1.8版本. 还有MbUnit,NUnit的[RollBack]特性与这个类似. 如果您还不熟悉怎么使用xUnit请先看这里介绍. 下面的代码使用 xUnit 代码变得更加简洁:
1: /// <summary>
2: /// Database unit testing with xUnit demo
3: /// </summary>
4: /// <remarks>http://wintersun.cnblogs.com </remarks>
5: public class TestDbWithxUnit
6: {
7: [Fact]
8: [AutoRollback]
9: public void Test_Add_One_Enity()
10: {
11: //arrange
12: var employee = this.CreateNewEmployee();
13: var employRepository = RepositoryHelper.GetEmployeeRepository();
14:
15: //act
16: employRepository.Add(employee);
17: employRepository.Save();
18:
19: //assert
20: var employeelist =
21: employRepository.Repository.Find(e => e.EmployeeID == employee.EmployeeID);
22: Assert.NotNull(employeelist);
23: Assert.Equal(new List<Employee> { employee }, employeelist.ToList());
24: }
25: }
上面的代码我们只需在方法上加一个AutoRollback的Attribute就可以了, 注意你先需要引用xunit.extensions.dll
|
|