测试不执行方法,除非我断言方法的返回值

jor*_*nbs 2 c# asp.net-mvc nunit unit-testing

好的,我有一个奇怪的问题.

我在C#Test项目中使用NUnit和Moq.我认为你可以忽略模拟对象,因为真正的问题在于UserManager.AddUser()没有被正确执行.

以下代码永远不会在UserManager.AddUser()的开头到达断点,因此由于NullPointerException而导致Assertion失败.

[Test]
enter code here
public void AddUser_NoPassword_GeneratesPassword()
    {
        //assert
        var userRepositoryFake = new Mock<IUserRepository>();
        userRepositoryFake.Setup(x => x.GetUser(It.IsAny<string>(), It.IsAny<bool>())).Returns((User)null);
        userRepositoryFake.Setup(x => x.SaveUser(It.IsAny<User>())).Returns(new Mock<User>().Object);

        var userManager = new UserManager(userRepositoryStub.Object);
        var createUserViewModel = new CreateUserViewModel { Username = "username" };

        //act
        var validationErrors = userManager.AddUser(createUserViewModel);

        //assert
        Assert.IsNotNullOrEmpty(createUserViewModel.Password);
    }
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加这个断言:

        //assert
        Assert.IsEmpty(validationErrors); //new assertion
        Assert.IsNotNullOrEmpty(createUserViewModel.Password);
Run Code Online (Sandbox Code Playgroud)

到达AddUser()中的断点,测试成功.似乎测试根本不执行AddUser(),除非它的返回值用于某些东西.

Jon*_*eet 5

我的猜测是这样AddUser实现的:

public IEnumerable<Error> AddUser(Model model)
{
    // Do some stuff
    if (foo)
    {
        yield return ...;
    }
    if (bar)
    {
        yield return ...;
    } 
    // More stuff
}
Run Code Online (Sandbox Code Playgroud)

换句话说,使用迭代器块.Iterator块是懒惰地执行的 - 代码只在请求第一个元素时才开始执行,即使这样,它也会在返回该元素时"暂停".

鉴于这不是幂等查询或类似的东西,我建议使用List<Error>你添加到内部然后在最后返回的内部实现方法会更有意义.这样,该方法将被执行一次,但是多次返回值被迭代.我怀疑这是预期的执行模式.