C#单元测试:覆盖方法的重写

3

我是一个对单元测试比较新的人,我想知道是否有一种内置的解决方案来解决以下问题。

我想要测试一个方法,在其中某个时刻需要测量硬件的输入。

var results = Measurement.MeasureAll();

当然,我希望在没有硬件的情况下进行测试。是否有一种方法可以在单元测试的范围内覆盖Measurement.MeasureAll()方法,以返回一些预定义的值?


2
你想编写针对接口而不是具体实现的程序。这样,你可以轻松地提供自己的仅用于测试的实现。 - matcheek
1
这个问题太宽泛了。你必须先提供一些代码。基本上,你想创建一些接口,可以提供一些虚拟实现来模拟你的硬件。但是如果你的方法是静态的,就没有办法做到这一点,你只能模拟虚拟成员(当然还有接口成员)。 - MakePeaceGreatAgain
你还应该看一下微软的单元测试框架[Fakes] https://msdn.microsoft.com/en-us/library/hh549175.aspx。如果你没有改变实现的选择,你可以shim MeasureAll方法的调用。 - TYY
1个回答

4
你需要模拟依赖项。这是你的依赖项:
Measurement

测量(Measurement)是什么?它来自哪里?为了使代码可单元测试,应该将测量(Measurement)提供给该代码。类似于这样:

public void MethodBeingTested(Measurement measurement)
{
    // use Measurement here
}

也许是这样:

或者这样:

public class SomeClass
{
    private Measurement TheMeasurement { get; set; }

    public SomeClass(Measurement theMeasurement)
    {
        TheMeasurement = theMeasurement;
    }

    public void MethodBeingTested()
    {
        // use TheMeasurement here
    }
}

然后,您的单元测试可以创建一个假/模拟/存根等Measurement并将其提供给测试。(有大量的模拟库可用于帮助实现此目的。我个人喜欢Moq和RhinoMocks。)该“模拟”版本将由测试定义,以特定且可预测的方式执行。然后,它将观察到正在测试的代码与模拟完全按照预期的方式进行交互。
现在,有些对象非常难以模拟。如果您展示的是static,情况可能尤为如此。(静态成员使单元测试变得非常困难。)这就是您需要将这样的对象包装在可模拟的包装器中的地方。例如,以下内容就足够简单:
public interface IMeasurement
{
    SomeType MeasureAll();
}

public class MyMeasurement
{
    // declare Measurement here?  some other context?

    public SomeType MeasureAll()
    {
        return Measurement.MeasureAll();
    }
}

这里的想法是,您的业务逻辑将与IMeasurement耦合,您完全控制和模拟/测试。然后,您可以提供包装类的模拟版本(由于使用接口而变得简单),而不必担心模拟实际依赖关系。

很不幸,我在此调用的是一个静态类(Measurement)。让我看看我是否理解你的意思。正确的方法是创建一个包装类MyMeasurement来包装这个静态类,并将其交给我想要进行单元测试的方法。在单元测试中,我只需将我的模拟类作为参数传递,它会替代原始的MeasureAll()方法,执行任何我希望的操作? - Tamaska Janos
@TamaskaJanos:在这种情况下使用包装器的理由更加充分。使用实例成员比使用静态成员更容易进行单元测试。包装器可以基于实例,并且可以在内部使用依赖项的静态成员。 - David
让我看看我是否正确理解了你的意思。正确的方法是为静态类创建一个包装类MyMeasurement,并将其传递给我想要进行单元测试的方法。在单元测试中,我只需将我的模拟类作为参数传递,而不是执行原始的MeasureAll()方法,而是执行我希望它执行的任何操作? - Tamaska Janos
@TamaskaJanos:在这种情况下,这就是我会做的方式。(当然,除了问题中没有提到的其他问题。)可能有多种方法,我不会假装我的是唯一可能的方法。但是根据我的经验,像这样的包装器极大地简化了测试。权衡之处在于,您无法达到100%的代码覆盖率,因为您仍然无法测试包装器本身。但是包装器只是一个传递,它没有任何有意义的逻辑可供测试。 - David
非常感谢!我会尝试一下! - Tamaska Janos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接