xUnit测试添加模型列表失败

时间:2014-05-27 13:43:10

标签: c# asp.net unit-testing xunit nancy

我正在使用xUnit来测试我的项目。我有一项测试,用于检查user是否添加了list users private readonly IJsonService _jsonService; private readonly IUserService _userService; [Fact] public void Add_User_To_User_List() { //Given _userService = new UserService(_jsonService, _guidService); _jsonService = Substitute.For<IJsonService>(); var _fakeUserJsonFile = "Users.json"; var _fakeNewUser = new User() { ID = new Guid(), FirstName = "Denis", LastName = "Menis" }; var _fakeUserList = new List<User> { new User() { ID = new Guid(), FirstName = "Paddy", LastName = "Halle" }, new User() { ID = new Guid(), FirstName = "Job", LastName = "Blogs" } }; var _fakeUpdatedUserList = new List<User> { new User() { ID = new Guid(), FirstName = "Paddy", LastName = "Halle" }, new User() { ID = new Guid(), FirstName = "Job", LastName = "Blogs" }, new User() { ID = new Guid(), FirstName = "Denis", LastName = "Menis" } }; _jsonService.DeserializeObject<User>(_fakeUserJsonFile).Returns(_fakeUserList); _jsonService.SerializeObject(_fakeUserJsonFile, _fakeUpdatedUserList).Returns(true); //When var result = _userService.AddUser(_fakeNewUser); //Then Assert.Contains(_fakeNewUser, _fakeUpdatedUserList); } 项,如下所示:

public bool AddUser(User user)
    {
        var userList = GetUsers();

        user.ID = _guidService.NewGuid();

        userList.Add(user);

        var serializeObject = _jsonService.SerializeObject(_fileName, userList);

        return serializeObject;
    }

现在我知道代码是有效的,因为我先写了它,但是当我运行测试时它失败了!下面是我将用户添加到用户列表的代码:

public List<User> GetUsers()
    {
        return _jsonService.DeserializeObject<User>(_fileName).ToList();
    }

GetUser方法:

private readonly IFileSystem _file;
    private readonly HttpContextBase _httpContext;
    private readonly ILogger _logger;

    public JsonService(IFileSystem file, HttpContextBase httpContext, ILogger logger)
    {
        _file = file;
        _httpContext = httpContext;
        _logger = logger;
    }

    public IEnumerable<T> DeserializeObject<T>(string fileName)
    {
        try
        {
            var relativeFileName = _httpContext.Server.MapPath(fileName);
            var readFile = _file.ReadAllText(relativeFileName);
            var list = JsonConvert.DeserializeObject<List<T>>(readFile);
            return list;
        }
        catch (Exception ex)
        {
            _logger.LogException(ex);
            return null;
        }
    }

反序列化方法:

public class FileSystem : IFileSystem
{
    public void WriteAllText(string path, string contents)
    {
        File.WriteAllText(path, contents);
    }

    public string ReadAllText(string path)
    {
        return File.ReadAllText(path);
    }
}

FileSystem类:

var serializeObject = _jsonService.SerializeObject(_fileName, userList);

当我运行测试时,AddUser方法中的{{1}}每次都返回false。

我认为这样做是因为即使它与预期结果的数据相同,但在内存中它是对同一数据的不同引用。

任何人都可以帮助我,我希望它返回相同的引用数据。如果我不是很清楚,我可以详细说明。感谢

1 个答案:

答案 0 :(得分:1)

你是绝对正确的,问题的根源在于_fakeUserList_fakeUpdatedUserList引用两个完全不同的对象。您已将_jsonService.SerializeObject配置为在true引用时返回_fakeUpdatedUserList - 但您实际上已将引用传递给(已修改的)_fakeUserList }。

基本上,_fakeUpdatedUserList完全没必要。您可以专注于_fakeUserList,因为这是提供给SUT的对象(可能是通过DeserializeObject<User>)。

例如:

[Fact]
public void Add_User_To_User_List()
{
    //Given
    _userService = new UserService(_jsonService, _guidService);
    _jsonService = Substitute.For<IJsonService>();

    var _fakeUserJsonFile = "Users.json";
    var _fakeNewUser = new User()
    {
        ID = new Guid(),
        FirstName = "Denis",
        LastName = "Menis"
    };

    var _fakeUserList = new List<User>
    {
        new User()
            {
                ID = new Guid(),
                FirstName = "Paddy",
                LastName = "Halle"
            },
        new User()
            {
                ID = new Guid(),
                FirstName = "Job",
                LastName = "Blogs"
            }
    };

    _jsonService.DeserializeObject<User>(_fakeUserJsonFile).Returns(_fakeUserList);
    _jsonService.SerializeObject(_fakeUserJsonFile, _fakeUserList).Returns(true); // Match the original _fakeUserList, since that is what gets passed in by the implementation

    //When
    var result = _userService.AddUser(_fakeNewUser);

    //Then
    Assert.Contains(_fakeNewUser, _fakeUserList); // Verify that the provided _fakeUserList has been modified
}

旁注:您实际上可以从此测试中删除大量详细信息,因为它们与正在测试的功能无关。例如,_fakeUserList最初可能为空 - 它不必包含任何虚拟值。并且您可以使用_fakeNewUser的默认值(即,未指定FirstName等),因为在此测试中它们根本没有被引用。

修改:感谢您发布其他代码(适用于GetUsers等)。此代码显示您在ToList()返回的IEnumerable<User>上调用DeserializeObject<User>。这就是您的模拟对象没有按预期运行的原因:ToList()返回的列表与_fakeUserList完全不同。

此外,我在测试中没有看到_fakeUserJsonFile被注入SUT的任何地方。因此,_fileName中的AddUser可能不是您所期望的。

要解决此问题,您需要修改设计(例如,不要调用ToList),或修改测试中的预期行为。虽然你可能想考虑前者的可能性,但后者可能更容易。

例如:

    // Match any filename (unless you have a way of getting _fakeUserJsonFile into the SUT)
    // Match any list, as long as it contains the new user
    _jsonService.SerializeObject(Arg.Any<string>(), Arg.Is<List<User>>(list => list.Contains(_fakeNewUser))).Returns(true);

    //When
    var result = _userService.AddUser(_fakeNewUser);

    //Then
    Assert.IsTrue(result); // Only returns true if the mock object is invoked as expected

    // There is no way to verify the following assertion, because the test has no way of accessing the "updated" list
    //Assert.Contains(_fakeNewUser, _fakeUserList);