2

我有一个方法调用,我正在单元测试。在该方法调用中,它会调用将引发错误的方法,因为它正在尝试与在单元测试运行时不可用的设备通信。有没有办法避免调用内部方法调用?

环境:IDE 中的 C# Visual Studio 2010 单元测试

4

7 回答 7

5

如果您正在对具有外部依赖项的类进行单元测试,那么您必须使用注入的接口隔离外部依赖项。

interface IDevice
{
    void Run();
}

interface IDeviceOperator
{
    void Operate();
}

class DeviceOperator : IDeviceOperator 
{
    private readonly IDevice _device;

    public DeviceOperator(IDevice device)
    {
        _device = device;
    }

    public void Operate()
    {
        _device.Run();

        // test other stuff here
    }
}

[TestFixture]
public class DeviceOperatorTests
{
    [Test]
    public void Test_DeviceOperator_Operate()
    {
        IDevice device = A.Fake<IDevice>(); // Using FakeItEasy 3rd party mocking framework syntax
        DeviceOperator deviceOperator = new DeviceOperator(device);

        deviceOperator.Operate();
    }
}
于 2013-05-15T16:11:17.303 回答
2

在进行单元测试时,您必须为所有外部依赖项创建模拟或存根。一个可以帮助你的框架是Moq(如果你想探索,它有很多模拟框架)。

这些模拟或存根只是提供必要的交互和数据以通过测试的外观。

如果您提供有关该不可用设备的更多详细信息,我们可能会为您提供更多帮助。

于 2013-05-15T16:03:06.523 回答
1

查看Michael Feathers 的《有效地使用遗留代码》一书 - 它有很多关于处理尚未进行单元测试的代码的建议。

书中介绍的可能方法:

  • 在接口中提取依赖项 - 理想的方法(参见 jamespconnor 的回答)
  • 使用标志绕过呼叫(参见 Colm Prunty 的回答)
  • 将该调用提取到虚拟方法中并覆盖在单元测试中使用的派生类中
  • 通过委托(可能比完整接口/派生的影响更小)

从类派生的示例:

public class WithComplexDependency
{
   public void DoSomething()
   {
     // Extract original code into a virtual protected method
     // dependency.MethodThatWillBreak();
     CallMethodThatWillBreak();
   }

   virtual protected void CallMethodThatWillBreak()
   {
      dependency.MethodThatWillBreak();
   }
}

在测试代​​码中从类派生并提供自己的实现:

public class WithMockComplexDependency : WithComplexDependency
{
   // may also need to add constructor to call original one.

   override protected void CallMethodThatWillBreak()
   {
      // do whatever is needed for your test
   }
}

...
WithComplexDependency testObject = new WithMockComplexDependency();
testObject.DoSomething(); // now does not call dependency.MethodThatWillBreak()
...
于 2013-05-15T16:49:15.187 回答
1

可能有更好的方法,但是有一次或两次我遇到过这种情况,一个方法调用另一个复杂的方法,并在您正在测试的方法的末尾放置一个可选参数,例如

public void DoSomething(int number, bool skipMethod= false)
{
    if(!skipMethod)
        MethodThatWillBreak();
{

这样在正常的运行过程中就可以了,但是在你的单元测试中你可以做到

DoSomething(2,true);

但实际上,这表明您需要对代码进行一些重构,因为您的单元测试应该只针对一个“单元”。如果您可以在不调用的情况下测试该方法,MethodThatWillBreak那么它首先在那里做什么。

于 2013-05-15T16:05:02.080 回答
0

您可能不想跳过外部。相反,您希望隔离外部依赖项,例如访问外部设备。有很多方法可以做到这一点。您可以使用第三方隔离框架,例如 Moq 或 RhinoMock 等 b. 您可以使用 Moles 框架(因为您使用的是 VS2010) - 将 .NET 方法替换为委托 http://research.microsoft.com/en-us/projects/moles/ c。付费隔离框架,例如 TypeMock。d。或者干脆手写在接口中使用的假实现,而您的测试使用假实现。

于 2013-05-16T08:13:41.053 回答
0

通常你会从你正在测试的类中提取外部依赖,并在你的单元测试中将它们与假的交换。您将隔离它们并测试您感兴趣的部分。我建议您研究控制反转以及许多模拟框架之一(MoqRhino Mocks等)

于 2013-05-15T16:06:14.193 回答
0

要正确进行单元测试,您应该将与设备的通信与要测试的类分离!在另一个实现接口的类中抽象与设备的partetalking,在被测对象的ctor中注入通信类,现在您可以从外部注入一个模拟实现并避免错误,mmock实现还可以记录对其的调用或以预定义的方式响应缓和测试。读取依赖注入和控制反转

于 2013-05-15T16:05:51.823 回答