是否可以将模拟对象用作另一种模拟方法的输入?

时间:2019-01-04 01:27:00

标签: c# tdd moq

我创建了一个以前的Test方法,该方法在单个Data Access上为两个​​模拟对象进行了设置,并且运行良好。又有一个具有相同场景的案例,但是结果失败了。

这是测试方法:

Diccionario

这是业务规则:

[Test]
public void UpdateUserPassword_WhenInputsAreCorrect_ReturnsQuerySuccessMessage()
    {
        UpdatePasswordModel input = new UpdatePasswordModel()
        {
            UserName = "john.doe",
            NewPassword = "password1", //password1
            PreviousPassword = "password" //password
        };

        Mock<IUserDataAccess> user = new Mock<IUserDataAccess>();
        Mock<IDailyTimeInDataAccess> timeIn = new Mock<IDailyTimeInDataAccess>();
        Mock<IDailyTimeOutDataAccess> timeOut = new Mock<IDailyTimeOutDataAccess>();

        user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");
        user.Setup(x => x.GetUser(input.UserName)).Returns(new User()
        {
            UserKey = 10000,
            UserName = "john.doe",
            UserPassword = "LTg9BIob8urwz643K5+pBA=="
        });

        ILoginBusinessRules app = new LoginBusinessRules(user.Object, timeIn.Object, timeOut.Object);

        var output = app.UpdateUserPassword(input);

        Assert.AreEqual("User record updated.", output);
    }

测试返回失败。进一步的调试告诉我,这里的这一行返回null:

public string UpdateUserPassword(UpdatePasswordModel model)
    {
        if (model == null)
        {
            return "No data to process.";
        }
        if (string.IsNullOrEmpty(model.UserName))
        {
            return "Username is empty.";
        }
        if (string.IsNullOrEmpty(model.NewPassword))
        {
            return "New Password is empty.";
        }
        if (string.IsNullOrEmpty(model.PreviousPassword))
        {
            return "Previous Password is empty.";
        }

        var user = _userDataAccess.GetUser(model.UserName);
        if (user == null)
        {
            return "User not found.";
        }

        if (user.UserPassword != EncryptPassword(model.PreviousPassword))
        {
            return "Previous password does not match.";
        }
        else
        {
            user.UserPassword = EncryptPassword(model.NewPassword);
            user.UpdateDttm = DateTime.Now;
            user.UpdateUserId = model.UserName;

            var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);

            return result;
        }
    }

任何帮助都将不胜感激!

2 个答案:

答案 0 :(得分:1)

Setup使用input.NewPassword,根据测试,它是

UpdatePasswordModel input = new UpdatePasswordModel() {
    //...
    NewPassword = "password1",
    //...
};

//...

user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");

//...

但是在被测方法中,该方法用另一个值调用

//...

user.UserPassword = EncryptPassword(model.NewPassword);

//...

var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);

与设置中预期的不匹配。

当未按预期方式调用模拟成员时,它将返回默认的返回类型,在这种情况下,返回类型为 null

您需要确保设置期望值中使用了正确的值

例如

user
    .Setup(x => x.UpdatePassword(10000, EncryptPassword(input.NewPassword)))
    .Returns("User record updated.");

或使用类似It.IsAny<T>()

的参数匹配器来放松对设置的期望
   user
    .Setup(x => x.UpdatePassword(10000, It.IsAny<string>()))
    .Returns("User record updated.");

答案 1 :(得分:0)

要回答帖子中的问题,可以,您可以使用任何与输入类型匹配的对象。您的代码并不真正知道“模拟”对象与“真实”对象之间的区别。