单元测试 - 是否应包装/模拟所有库依赖项

时间:2017-08-25 11:33:10

标签: c# unit-testing mocking

我正在编写一个可以读/写Json文件的类(C#)。

我已经在模拟单元测试的文件系统,我现在想知道是否还应该包装并模拟在创建时传递给类的序列化程序对象。

我理解文件系统必须被模拟,否则我将不得不为测试创建文件,这将使它们进行集成测试。

我是否还应该在界面中包装序列化程序并嘲笑它?如果是这样,我是否还应该包装/模拟我写的其他类中的每个依赖项?如果我使用外部类中的许多方法将它们包装在接口中似乎是一个很大的时间下沉。

编辑:

public class Sources
{
    private readonly IDirectory _directory;
    private readonly IFile _file;

    public Sources(IDirectory directory, IFile file)
    {
        _directory = directory;
        _file = file;
    }

    public LibrarySource GetSource(string filePath)
    {
        using (var streamReader = _file.OpenText(filePath))
        using (var jsonTextReader = new JsonTextReader(streamReader.StreamReaderInstance))
        {
            JsonSerializer serializer = new JsonSerializer();
            var sourceDto = serializer.Deserialize<LibrarySourceDto>(jsonTextReader);
            return SourceMapper.Map(sourceDto);
        }
    }
}

在这段代码中,我在类中创建了JsonSerializer对象。这是一个依赖项,但我不确定它是否应该被包装/模拟并注入类构造函数中,或者只是保留原样。如果我将它包装在接口中并发现我需要使用类中的更多方法,那么编辑接口本身可能会非常耗时。

1 个答案:

答案 0 :(得分:1)

这是&#34;它取决于&#34;场景。模仿/包装每一个依赖可能都是过度杀伤,但这个问题太过宽泛而无法涵盖在这个问题中。

对于这个特殊情况,在我看来,根据我的经验,串行器代码不需要抽象。如果您决定使用另一个,则可以编辑该方法,而不会影响该类的依赖项。 Sources类无论其如何执行,都会履行提供源的唯一责任。哪个是重要的。

那就是说,我也有过IJsonSerializer作为依赖的情况。但同样,完全取决于你的选择。

/// <summary>
/// Provides JSON Serialize and Deserialize.
/// </summary>
public interface IJsonSerializer : ISerializer {

}

/// <summary>
/// Serialization interface that supports serialize and deserialize methods
/// </summary>
public interface ISerializer {
    /// <summary>
    /// Serialize the specified object into a string
    /// </summary>
    /// <param name="obj">object to serialize</param>
    string Serialize(object obj);
    /// <summary>
    /// Deserialize a string into a typed object
    /// </summary>
    /// <typeparam name="T">type of object</typeparam>
    /// <param name="input">input string</param>
    T Deserialize<T>(string input);
}

其中实现包含了用于项目的JSON API。

例如

public class Sources {
    private readonly IDirectory _directory;
    private readonly IFile _file;
    private readonly IJsonSerializer serializer; 

    public Sources(IDirectory directory, IFile file, IJsonSerializer serializer) {
        _directory = directory;
        _file = file;
        this.serializer = serializer;
    }

    public LibrarySource GetSource(string filePath) {
        var sourceDto = serializer.Deserialize<LibrarySourceDto>(_file.ReadAllText(filePath));
        return SourceMapper.Map(sourceDto);
    }
}

序列化程序的实现取决于您。它可能需要原始的json,路径等等。