测试单元测试中是否存在保存方法

时间:2012-08-06 15:05:30

标签: asp.net-mvc unit-testing repository

我开始在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);            
        }

1 个答案:

答案 0 :(得分:0)

您必须注意不要编写一堆只测试测试存储库的单元测试。

考虑以下情况:

  1. 您有一个服务方法,应该将项目添加到您的存储库。
  2. 您的单元测试调用此方法,您应该验证是否在存储库上调用了相应的“AddX”方法。
  3. 这是一个有效的单元测试场景,为了测试它你可以使用你的测试库。由于它是您的测试对象,因此您可以完全控制它。您可以公开诸如“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());
    }