测试单元测试是否存在保存方法
我从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);
}
你一定要小心,不要写一堆的测试你的测试库的单元测试。
考虑以下情形:
- 你有一个服务的方法,是应该将项目添加到您的存储库。
- 你的单元测试调用了这个方法,你应该验证在仓库上调用了合适的“AddX”方法。
这是一个有效的单元测试场景,为了测试它你可以使用你的测试库。既然它是你的测试对象,你完全可以控制它。您可以公开诸如“AddXMethodCallCount”之类的属性。
随着时间的推移,你会发现自己编写了大量的样板代码。另一种选择,我强烈建议,是使用模拟框架:
https://*.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());
}
在我的仓库中,我有一个创建方法,它向集合中添加一个项目,并保存对数据库所做更改的保存方法。控制器的创建方法应使用存储库的create和save方法。我可以使用测试存储库测试create方法,因为项目已添加到集合中。但我无法测试控制器是否将保存方法命中以将更改写入数据库,这在我看来非常重要。 – 2012-08-11 18:51:43
发布您的代码将帮助我更好地回答您的问题。我的回答意思是,如果你的测试在TEST库上调用了一个方法,那么你并没有真正测试任何东西。什么是您的测试正在调用的生产代码? – 2012-08-12 03:36:15
谢谢你帮助我!我添加了代码。我想测试的是如果控制器命中存储库的save()方法。 – 2012-08-12 18:56:48
看看嘲笑和BDD。 BDD是为这种事情设计的。 – 2012-08-06 15:19:15