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

C# 单元测试-是否应包装/模拟所有库依赖项,c#,unit-testing,mocking,C#,Unit Testing,Mocking,我正在编写一个类来读/写Json文件 我已经在模拟文件系统进行单元测试,现在我想知道是否也应该包装和模拟创建时传递到类中的序列化器对象 我知道必须模拟文件系统,否则我必须为测试创建文件,这将使它们成为集成测试 我是否也应该在接口中包装序列化程序并模拟它?如果是这样,我是否也应该包装/模拟我编写的其他类中的每个依赖项?如果我使用的是来自外部类的许多方法,那么将它们包装在接口中看起来就像是一个巨大的时间接收器 编辑: 在这段代码中,我在类中创建JsonSerializer对象。这是一个依赖项,但我不

我正在编写一个类来读/写Json文件

我已经在模拟文件系统进行单元测试,现在我想知道是否也应该包装和模拟创建时传递到类中的序列化器对象

我知道必须模拟文件系统,否则我必须为测试创建文件,这将使它们成为集成测试

我是否也应该在接口中包装序列化程序并模拟它?如果是这样,我是否也应该包装/模拟我编写的其他类中的每个依赖项?如果我使用的是来自外部类的许多方法,那么将它们包装在接口中看起来就像是一个巨大的时间接收器

编辑:


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

这是一个依赖于它的场景。嘲弄/包装每个依赖项可能有点过头了,但这太宽泛了,在这个问题中无法涵盖

在我看来,根据我的经验,对于这种特殊情况,不需要抽象序列化程序代码。如果您决定使用不同的方法,您可以只编辑该方法而不影响类的依赖项。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、路径等。

这是一个视情况而定的场景。嘲弄/包装每个依赖项可能有点过头了,但这太宽泛了,在这个问题中无法涵盖。试着用a来缩小你的问题范围,让我们看看社区是否能帮助你。在我看来,根据我的经验,序列化程序代码不需要抽象。如果您决定使用不同的方法,您可以只编辑该方法而不影响类的依赖项。也就是说,我也有过将IJsonSerializer作为依赖项的情况。但是,选择什么完全取决于你自己。
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);
    }
}