我如何模拟第 3 方库的 return 类型的工厂方法?

How can i mock a return type of a factory method of a 3rd party library?

我正在开发使用 Mono.Cecil 加载程序集的工具。我有以下工厂,return 是一个名为 binary 的对象,它依赖于负责使用 AssemblyDefinintion.ReadAssembly 方法加载程序集的接口。

我对单元测试完全陌生,我需要对 GetBinary 方法进行单元测试。

internal sealed class DotNetBinaryFactory : IBinaryFactory
{
    private readonly IBinaryLoader binaryLoader;
    public DotNetBinaryFactory(IBinaryLoader binaryLoader)
    {
        this.binaryLoader = binaryLoader;
    }

    [NotNull] public Binary GetBinary([NotNull] FilePath path)
    {
        var assembly = binaryLoader.LoadBinary(path);
        return BinaryUtils.GetBinary(assembly);
    }
}

这里是IBinaryLoader依赖实现

internal interface IBinaryLoader
{
    AssemblyDefinition LoadBinary(FilePath path);
}

internal sealed class DotnetBinaryLoader : IBinaryLoader
{
    public AssemblyDefinition LoadBinary([NotNull] FilePath path)
    {
        try
        {
            return AssemblyDefinition.ReadAssembly(path.Path);
        }                
        catch (Exception)
        {
            Console.WriteLine("Exception in loading Assembly From : " + path.Path);
            throw;
        }
    }
}

所以为了单元测试 GetBinary 方法,我需要模拟 IBinaryLoader 并将 LoadBinary 方法设置为 return 虚拟 AssemblyDefinition 对象,但我可以'创建一个。

这是我试过的

[Test]
public void GetDotnetBinary_AssemblyDefinitionInput_ReturnCorrectDotnetFrameworkBianry()
{
    var path = FilePath.GetRandom();
    var mockedAssemblyDef = new Mock<AssemblyDefinition>();
    var binaryLoader = new Mock<IBinaryLoader>();
    binaryLoader.Setup(m => m.LoadBinary(path)).Returns(mockedAssemblyDef.Object);
}

您需要创建服务模拟,而不是数据模拟。在您的情况下 AssemblyDefinition 是数据,也是 sealed 。模拟不适用于具体数据 类。您对“服务”的模拟 binaryLoader 看起来不错。

您需要做的是以另一种方式创建您的虚拟 AssemblyDefinition,然后 return。我不熟悉 Mono.Cecil,但您似乎可以使用静态 Create() 方法。获得所需的实例后,测试的其余部分应该就位。

你最终会得到类似

的东西
[Test]
public void GetDotnetBinary_AssemblyDefinitionInput_ReturnCorrectDotnetFrameworkBianry()
{
    // arrange
    var path = FilePath.GetRandom();
    var assemblyDef = AssemblyDefinition.Create(...); // or however your create a real one
    var binaryLoader = new Mock<IBinaryLoader>();
    binaryLoader.Setup(m => m.LoadBinary(path)).Returns(assemblyDef);
    var factory = new DotNetBinaryFactory(binaryLoader);

    // act
    var result = factory.GetBinary(path);

    // assert
    // your assertions here...
}

我还看到您的类型是内部类型。假设您的测试在不同的程序集中,您将必须使内部结构对该程序集可见。这是通过在源程序集中放置一个 [InternalsVisibleTo] 属性来完成的。