我开始在asp.net mvc 4框架中进行单元测试。
我有一个包含基本crud方法和save方法的存储库。当我创建单元测试时,我创建了一个测试存储库并测试是否例如添加了集合中的项目。一切顺利但我无法测试是否命中了save方法。
我尝试将一个布尔属性添加到测试存储库,如果遇到.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);
}
答案 0 :(得分:0)
您必须注意不要编写一堆只测试测试存储库的单元测试。
考虑以下情况:
这是一个有效的单元测试场景,为了测试它你可以使用你的测试库。由于它是您的测试对象,因此您可以完全控制它。您可以公开诸如“AddXMethodCallCount”之类的属性或类似的属性。
随着时间的推移,你会发现自己编写了大量的测试代码。我强烈建议的替代方案是使用模拟框架:
https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use
需要一些时间来适应,但一旦你得到它,它将显着加快你的单位测试。
如果您还不想使用模拟,但仍希望实现验证是否调用Save()的目标,我建议只添加一个公开公开的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);
}
为了让我的示例完整,让我告诉你如果你使用像Moq这样的模拟框架会是什么样子。您可以看到更多示例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());
}