2012-08-06 128 views
1

我从asp.net mvc 4框架中的单元测试开始。测试单元测试是否存在保存方法

我得到了一个基本的crud方法和保存方法的存储库。当我创建单元测试时,我创建了一个测试存储库并测试(例如)添加到集合的项目。这一切顺利,但我无法测试保存方法是否被击中。

我试图添加一个布尔属性到测试库,如果命中.save(),它将被设置为true。但是接下来我需要更改界面以及数据库存储库。这在我看来既不实际也不是最佳实践。

什么是测试这个最好的方法?预先感谢您的回答。

我的代码:

假仓库:

public class TestUserRepository : IUserManagementRepository 
    { 
     /// <summary> 
     /// entries used used for testing 
     /// </summary> 
     private List<User> _entities; 

     /// <summary> 
     /// constructor 
     /// </summary> 
     public TestUserRepository() 
     { 
      _entities = new List<User>(); 
      _entities.Add(new User 
      { 
       Id = 1, 
       InsertDate = DateTime.Now, 
       LastUpdate = DateTime.Now, 
       Username = "TestUserName", 
       Password = "TestPassword" 
      }); 
     } 
... 

public void Create(User task) 
     { 
      _entities.Add(task); 
     } 

public void Save() 
     { 
      //do nothing 
     } 
    } 

控制器测试:

[HttpPost] 
     public ActionResult Create(User user) 
     { 
      if (ModelState.IsValid) 
      { 
       _repository.Create(user); 
       _repository.Save(); 
       return RedirectToAction("Index"); 
      } 
      else 
      { 
       return View(user); 
      } 

     } 

和测试

[TestMethod()] 
     public void CreateTest() 
     { 
      IUserManagementRepository repository = new TestUserRepository(); 
      UserController controller = new UserController(repository); 
      User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" }; 
      ActionResult actionResult = controller.Create(user); 
     User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>(); 

      Assert.IsNotNull(actionResult); 
      Assert.AreEqual(user, returnedUser);    
     } 
+1

看看嘲笑和BDD。 BDD是为这种事情设计的。 – 2012-08-06 15:19:15

回答

0

你一定要小心,不要写一堆的测试你的测试库的单元测试。

考虑以下情形:

  1. 你有一个服务的方法,是应该将项目添加到您的存储库。
  2. 你的单元测试调用了这个方法,你应该验证在仓库上调用了合适的“AddX”方法。

这是一个有效的单元测试场景,为了测试它你可以使用你的测试库。既然它是你的测试对象,你完全可以控制它。您可以公开诸如“AddXMethodCallCount”之类的属性。

随着时间的推移,你会发现自己编写了大量的样板代码。另一种选择,我强烈建议,是使用模拟框架:

https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use

这需要一些时间来适应,但一旦你得到它,它会显著加快您的单元测试。

如果你不想用嘲讽的是,但希望仍实现您验证是否保存()被调用的目标,我会建议只是增加了公开曝光SaveMethodCallCount属性:

public class TestUserRepository : IUserManagementRepository 
{ 

... 


public SaveMethodCallCount {get; set;} 

... 
public void Save() 
    { 
     SaveMethodCallCount++; 
    } 
} 

这是有效的,因为在你的单元测试中你可以说:

TestUserRepository repository = new TestUserRepository();

只要传入的参数实现了IUserManagementRepository接口,UserController并不在意。控制器通过接口与存储库对象交互,但单元测试不需要,而TestUserRepository作为一个测试类,可以有更多的功能,而不必通过接口公开。

所以,你的测试可能看起来像:

[TestMethod()] 
    public void CreateTest() 
    { 
     TestUserRepository repository = new TestUserRepository(); 
     UserController controller = new UserController(repository); 
     User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" }; 
     ActionResult actionResult = controller.Create(user); 
    User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>(); 

     Assert.IsNotNull(actionResult); 
     Assert.AreEqual(user, returnedUser); 
     Assert.AreEqual(1, repository.SaveMethodCallCount); 
    } 

为了让我的例子完成后,让我告诉你这是什么样子,如果你使用的模拟框架,像起订量。你可以看到更多的例子here。示例测试方法使用Moq和Arrange/Act/Assert,并且只测试一件事 - 当调用Create()时调用Save()。

[TestMethod()] 
public void Test_SaveCalledWhenCreateCalled() 
{  
    // Arrange 
    // First, instead of creating an instance of your test class, you create a mock repository. 
    // In fact, you don't need to write any code, the mocking framework handles it. 
    var mockRepository = new Mock<IUserManagementRepository>(); 
    // and pass the mock repository (which implements the IUserManagementRepository) to your controller 
    UserController controller = new UserController(mockRepository); 

    // Act 
    ActionResult actionResult = controller.Create(user); 

    // Assert 
    // see how easy it is to do with a mocking framework: 
    mockRepository.Verify(rep => rep.Save(), Times.AtLeastOnce()); 
} 
+0

在我的仓库中,我有一个创建方法,它向集合中添加一个项目,并保存对数据库所做更改的保存方法。控制器的创建方法应使用存储库的create和save方法。我可以使用测试存储库测试create方法,因为项目已添加到集合中。但我无法测试控制器是否将保存方法命中以将更改写入数据库,这在我看来非常重要。 – 2012-08-11 18:51:43

+0

发布您的代码将帮助我更好地回答您的问题。我的回答意思是,如果你的测试在TEST库上调用了一个方法,那么你并没有真正测试任何东西。什么是您的测试正在调用的生产代码? – 2012-08-12 03:36:15

+0

谢谢你帮助我!我添加了代码。我想测试的是如果控制器命中存储库的save()方法。 – 2012-08-12 18:56:48