C# 如果调用了外部库的方法,则使用Moq进行测试

C# 如果调用了外部库的方法,则使用Moq进行测试,c#,unit-testing,moq,C#,Unit Testing,Moq,对于一个项目,我使用的是MEF框架的CompositeContainer类。现在我想做一个单元测试(使用moq)来验证是否调用了composepart(AttributedModelServices中的扩展方法) 仅仅用moq模拟它是行不通的,因为该方法不是虚拟的。我找到了一些方法来实现这一点,但所有这些方法都使我改变了CompositeContainer类,而我不能这样做 在moq中是否有方法测试是否调用了外部第三方库的非虚拟方法 提前感谢您的回复 示例代码: public void Load

对于一个项目,我使用的是MEF框架的CompositeContainer类。现在我想做一个单元测试(使用moq)来验证是否调用了composepart(AttributedModelServices中的扩展方法)

仅仅用moq模拟它是行不通的,因为该方法不是虚拟的。我找到了一些方法来实现这一点,但所有这些方法都使我改变了CompositeContainer类,而我不能这样做

在moq中是否有方法测试是否调用了外部第三方库的非虚拟方法

提前感谢您的回复

示例代码:

public void Load(string path, CompositionContainer container)
{           
    container.ComposeParts(this);           
}
此处容器来自MEF库,ComponentModel.Composition命名空间中的ComponentParts扩展方法:

//
// Summary:
//     Creates composable parts from an array of attributed objects and composes
//     them in the specified composition container.
//
// Parameters:
//   container:
//     The composition container to perform composition in.
//
//   attributedParts:
//     An array of attributed objects to compose.
public static void ComposeParts(this CompositionContainer container, params object[] attributedParts);

它是在类中实现的Load方法吗?你考虑从那里移除它吗?考虑到单一责任原则,看起来你们班做得太多了

我建议您拆分功能—您的类执行它需要执行的任何业务逻辑。还有另一个“infrastructure”类,负责组成容器——在您的例子中,获取类的实例,并在容器中注册它


你会有几乎相同的问题,但在另一个地方。这个“新”的地方将更加关注它的功能,你可以使用一个真正的容器单独测试它,并检查它是否组成了正确的部分。

我不认为可以直接验证第三方库方法是否被Moq调用,但是您可以检查调用该方法的副作用。由于您使用MEF在运行时检索实现,我将测试您的类型是否正确加载。所以如果你有这样的东西:

public interface IInterfaceToCompose
{
    string MethodToCreate();
}

[Export(typeof(IInterfaceToCompose))]
public class ConcreteImplementation1 : IInterfaceToCompose
{
    public string MethodToCreate()
    {
        return "Implementation 1";
    }
}

[Export(typeof(IInterfaceToCompose))]
public class ConcreteImplementation2 : IInterfaceToCompose
{
    public string MethodToCreate()
    {
        return "Implementation 2";
    }
}
[ImportMany(typeof(IInterfaceToCompose))]
public IInterfaceToCompose ComposedItems { get; set; }

[Test]
public void WhenComposingTheComposedItems_ShouldLoadExportedTypes()
{
    Load("testPath", YourContainer);

    Assert.AreEqual(2, ComposedItems.Count());
}
然后,您可以编写一个如下所示的测试:

public interface IInterfaceToCompose
{
    string MethodToCreate();
}

[Export(typeof(IInterfaceToCompose))]
public class ConcreteImplementation1 : IInterfaceToCompose
{
    public string MethodToCreate()
    {
        return "Implementation 1";
    }
}

[Export(typeof(IInterfaceToCompose))]
public class ConcreteImplementation2 : IInterfaceToCompose
{
    public string MethodToCreate()
    {
        return "Implementation 2";
    }
}
[ImportMany(typeof(IInterfaceToCompose))]
public IInterfaceToCompose ComposedItems { get; set; }

[Test]
public void WhenComposingTheComposedItems_ShouldLoadExportedTypes()
{
    Load("testPath", YourContainer);

    Assert.AreEqual(2, ComposedItems.Count());
}
您真正想要测试的(IMO)是您正确地创建了组合类,并且它们都可以由MEF CompositionContainer加载


第二个好的测试是进行初始加载,使用第三个实现者添加一个dll,并确保最终计数为3(系统是否动态加载新模块)。这将捕获错误,例如忘记将新实现的属性设置为Export属性,并确保类在发生更改时正确拾取更改。

如果只想检查是否调用了方法,可以将CompositionContainer包装在名为ICompositionContainer的包装器接口中,该接口具有相同的方法签名。然后使用Moq,您可以断言调用了该方法:

mock.Verify(cc => cc.ComposeParts(), Times.Once());
这里的负面影响是,您正在创建一个接口来隐藏一个事实,即原始实现没有为您实现一个接口

示例代码现在是:

public void Load(string path, ICompositionContainer container)
{           
    container.ComposeParts(this);           
}

在.NET framework中,还有一些其他项目的例子需要测试类,例如。

您能展示一个您正在调用的扩展方法的例子吗?您试图测试一个不是您自己的类是否调用了一个方法?也许您测试的是错误的代码段,也许您应该测试在应用程序上调用此方法的效果。我添加了一个示例,以及我想测试的是load方法是否调用CompositionContainer的ComposeParts方法。这与模拟接口完全相同,但现在使用的是外部库中的一个具体类。这正是您正在描述的实际类,但由于我想给出一个简单的示例,所以我给出了此代码,以保持清楚。我确实可以使用该函数并查看它是否加载模块。但我在技术上也在测试第三方代码。我在想,如果没有它,我是否能做到这一点。这里我唯一需要知道的是:“它调用方法了吗?”。如果该方法有效与否是另一个单元测试(以及其他人关心的问题)。我能想到的下一个最好的方法是使用名为ComposedParts的方法制作包装器接口ICompositionContainer,您可以在生产/集成测试场景中发送一个模拟测试和真实事物的包装版本。然后您可以断言接口方法已被调用。虽然这不能证明你的包装器类是正确的,但它可以证明一个采用ICompositionContainer类型接口的对象调用了ComposeParts方法(听起来就像你想要的那样)。我希望我可以跳过虚拟模块的设置来测试该方法,但这似乎是唯一的方法。创建包装器和接口只是将问题转移到包装器,并向测试类添加不必要的代码。所以我选择这个答案。谢谢你的帮助。