c# – 我的单元测试是否太在乎了

我对我的单元测试方法有两个顾虑:

>我在一种测试方法中测试过多吗?
>我的测试方法名称如何反映所有测试期望?

我问自己,当我的方法名称是:ReturnInvalidModelState,然后我的其他两个断言是不正确的.至少关于方法名称……

[Test]
public void Create_TemplatealreadyExists_ReturnInvalidModelState()
{
    // ARRANGE
    Templateviewmodel templateviewmodel = new Templateviewmodel { 
        Name = "MyTest" 
    };

    Mock<ITemplateDataProvider> mock1 = new Mock<ITemplateDataProvider>();
    Mock<IMappingEngine> mock2 = new Mock<IMappingEngine>();

    TemplateController controller = 
        new TemplateController(mock1.Object,mock2.Object);
    mock1.Setup(m => m.TemplateExists("MyTest")).Returns(true);
    // Set ModelState.IsValid to false
    controller.ModelState.AddModelError("Name","This name already exists.");

    // ACT
    ActionResult result = controller.Create(templateviewmodel);

    // ASSERT
    Assert.IsFalse(controller.ModelState.IsValid);
    Assert.isinstanceOfType(typeof(PartialViewResult),result);
    Assert.AreEqual(templateviewmodel,((PartialViewResult)result).Model);
}

[HttpPost]
public ActionResult Create(Templateviewmodel templateviewmodel)
{
    if (ModelState.IsValid
        && !_templateDataProvider.TemplateExists(templateviewmodel.Name))
    {

        Template template = 
            Mapper.Map<Templateviewmodel,Template>(templateviewmodel);

        _templateDataProvider.AddTemplate(template);
        return new JsonNetResult(new { success = true });
    }
    ModelState.AddModelError("Name","This name already exists.");
    return PartialView(templateviewmodel);
}

解决方法

是的,我认为你正在测试太多东西.

首先重命名您的测试方法.您的方法签名应描述操作,方案和预期结果.

如果我要重命名你的方法,那么最终会得到以下结果:

public void Create_DuplicateTemplate_ModelStateIsInvalidAndReturnsPartialViewResultAndPartialViewResultOfTypeTemplateviewmodel() 
{ 
}

您的测试涉及三件事,而不是一件事.当它失败时,你不会马上知道它失败的原因.

考虑将其重新分解为较小的测试并封装一些排列逻辑,以便可以重复使用.

编辑:

关于单一测试方法的单一断言,您在评论中提出了一个很好的观点.我同意你的意见,尽管听起来不错,但通常还不够.

假设我有以下操作方法

[HttpPost]
public ActionResult Register(NewUserviewmodel newUser)
{
    if (!ModelState.IsValid)
        return View(newUser);

    var newUserDTO = Mapper.Map<NewUserviewmodel,NewUserDTO>(newUser);
    var userDTO = UserManagementService.RegisterUser(newUserDTO);

    var result = Mapper.Map<UserDTO,Userviewmodel>(userDTO);

    TempData.Add("RegisteredUser",result);
    return RedirectToAction("RegisterSuccess");
}

我对此方法进行了以下单元测试:

[TestMethod]
        public void Register_HttpPost_Validviewmodel_ReturnsRegisterSuccess()
        {
            // Arrange
            var autoMapperMock = this.mockRepository.Dynamicmock<IMapper>();
            var userManagementServiceMock = this.mockRepository.Dynamicmock<IUserManagementService>();

            var invalidRegistrationviewmodel = new NewUserviewmodel
            {
                LastName = "Lastname",FirstName = "Firstname",Username = null
            };

            autoMapperMock.Expect(a => a.Map<UserDTO,Userviewmodel>(Arg<UserDTO>.Is.Anything)).Repeat.Once().Return(null);
            autoMapperMock.Expect(a => a.Map<NewUserviewmodel,NewUserDTO>(Arg<NewUserviewmodel>.Is.Anything)).Repeat.Once().Return(null);
            userManagementServiceMock.Expect(s => s.RegisterUser(Arg<NewUserDTO>.Is.Anything)).Repeat.Once();

            autoMapperMock.Replay();

            var controller = new AccountController
            {
                Mapper = autoMapperMock,UserManagementService = userManagementServiceMock
            };

            this.mockRepository.ReplayAll();

            // Act
            var result = (RedirectToRouteResult)controller.Register(invalidRegistrationviewmodel);

            // Assert
            Assert.IsTrue((string)result.RouteValues["Action"] == "RegisterSuccess");
        }

如您所见,我对我的模拟设置了多个期望:

>我希望AutoMapper被调用两次
>我希望一次调用UserManagementService

在测试结束时,我有一个断言,检查用户是否被重定向到正确的路由.

那么我在哪里检查我的断言?我创建了另一种方法来确保满足我的期望:

[TestCleanup]
    public void Cleanup()
    {
        try
        {
            this.mockRepository.VerifyAll();
        }
        finally
        {                
        }
}

所以你是对的,我有三个断言而不是一个断言,但是我以这样的方式构造我的代码,所以看起来我只有一个断言.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...