将c#中的json模拟为单元测试

时间:2017-11-24 10:39:49

标签: c# json mocking

我目前正在尝试对下面的代码进行单元测试,并且真的不知道该去哪里。读了一下之后,我想我需要使用mocking / faking并初始化一个假的json目录,我可以将其传递给单元测试,虽然模拟似乎非常复杂,我似乎无法理解它。对此的任何帮助都会很棒。 提前致谢, K

        public static string ShowLocation = Directory.GetCurrentDirectory() +  @"\Database\Shows.txt";
    public static string GoldMemberLocation = Directory.GetCurrentDirectory() + @"\Database\GoldMembers.txt";

    /// <summary>
    /// Deletes a specific show from the database.
    /// </summary>
    /// <param name="show"></param>
    public static void DeleteShow (Show show)
    {
        if (Directory.Exists(ShowLocation))
        {
            string json = File.ReadAllText(ShowLocation);

            List<Show> data = JsonConvert.DeserializeObject<List<Show>>(json);
            data.Remove(show);

            json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(ShowLocation, json);
        }
        else
        {
            File.WriteAllText(ShowLocation, String.Empty);
            SaveShow(show);
        }
    }

    /// <summary>
    /// Saves a new Show.
    /// </summary>
    /// <param name="show"></param>
    public static void SaveShow(Show show)
    {
        if (File.Exists(ShowLocation))
        {
            string json = File.ReadAllText(ShowLocation);

            var data = new List<Show>();

            FileInfo f = new FileInfo(ShowLocation);
            if (f.Length > 0)
            {
                data = JsonConvert.DeserializeObject<List<Show>>(json);
            }

            data.Add(show);

            json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(ShowLocation, json); 
        }
        else
        { 
            var data = new List<Show>();

            data.Add(show);

            var json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(ShowLocation, json);
        }
    }

    /// <summary>
    /// Loads all the shows.
    /// </summary>
    /// <returns></returns>
    public static List<Show> LoadShows()
    {
        if (File.Exists(ShowLocation))
        {
            string json = File.ReadAllText(ShowLocation);

            List<Show> data = JsonConvert.DeserializeObject<List<Show>>(json);

            return data;
        }
        else
        {
            File.WriteAllText(ShowLocation, String.Empty);
            return new List<Show>();
        }

    }

    /// <summary>
    /// Deletes a specific gold member.
    /// </summary>
    /// <param name="goldMember"></param>
    public static void DeleteGoldMember(GoldMember goldMember)
    {
        if (File.Exists(GoldMemberLocation))
        {
            string json = File.ReadAllText(GoldMemberLocation);

            List<GoldMember> data = JsonConvert.DeserializeObject<List<GoldMember>>(json);
            data.Remove(goldMember);

            json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(GoldMemberLocation, json);
        }
        else
        {
            File.WriteAllText(GoldMemberLocation, String.Empty);
        }
    }

    /// <summary>
    /// Saves a new Gold member
    /// </summary>
    /// <param name="goldMember"></param>
    public static void SaveGoldMembers (GoldMember goldMember)
    {

        if (File.Exists(GoldMemberLocation))
        {
            string json = File.ReadAllText(GoldMemberLocation);
            var data = new List<GoldMember>();

            FileInfo f = new FileInfo(GoldMemberLocation);
            if (f.Length > 0)
            {
                data = JsonConvert.DeserializeObject<List<GoldMember>>(json);
            }

            data.Add(goldMember);

            json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(GoldMemberLocation, json);
        }
        else
        {
            var data = new List<GoldMember>();
            data.Add(goldMember);

            var json = JsonConvert.SerializeObject(data.ToArray());

            File.WriteAllText(GoldMemberLocation, json);
        }

    }

1 个答案:

答案 0 :(得分:1)

好的,停止测试的是文件IO。因此,您需要将这些方法提取到接口,然后模拟该接口。

然后设置您希望这些模拟方法返回的内容。

e.g。

// A concrete implementation you will use at runtime.
public class FileHelper : IFileHelper
{
    bool DirectoryExists(string location) => Directory.Exists(location);
    string ReadAlltext(string location) => File.ReadAllText(location);
    void WriteAlLText(string location, string text) => File.WriteAlLText(location, text);
}

public interface IFileHelper
{
    bool DirectoryExists(string location);
    string ReadAlltext(string location);
    WriteAllText(string location, string text);
}
[TestMethod]
public void TestDeleteShow()
{
    // Create a mock of your FileHelper and setup
    // the methods and what you want them to return.
    Mock<IFileHelper> fileHelper = new Mock<IFileHelper>();
    fileHelper.Setup(x=>x.DirectoryExists).Returns(true);
    fileHelper.Setup(x=>x.ReadAllText).Returns( /* put some text in here */);
    string testLocation = "foo";
    Foo.DeleteShow(testLocation);

    // Verify the methods on your mock were called, as expected.
    fileHelper.Verify(x=>x.WriteAlLText(It.IsAny<string>(), string.Empty));
}

然后,您可以验证是否使用某些参数调用了某些方法。我的例子是使用Moq。

例如,您可以设置DirectoryExists返回false的测试,然后您可以验证File.WriteAllText是否使用空字符串和正确的位置进行调用。等

上面的评论说这不会测试任何逻辑......它正在运行逻辑,因为它可以设置为测试如果他传入一个不存在的目录,你可以断言在那里创建了一个文件位置,它是空的。如果确实存在,则可以断言它调用方法但传入正确的内容。

这是该方法中唯一的逻辑......当然,您可以测试File.WriteAllLines的工作原理,但它是一个.net库方法。如果你正在测试.net框架你做错了..类似的,不需要测试JSonConvert ....在我给你一个例子的方法中,你正在测试你得到一个不同的动作的逻辑在目录存在的情况下,这是该方法中唯一的逻辑....