TDD - 为第三方代码创建测试

9
如果我要测试的方法或过程依赖于第三方代码,那么我该如何创建单元测试呢?比方说,我有一个方法使用了来自第三方源的类,这些类需要在功能测试中进行设置。我应该如何处理呢?大多数情况下,第三方依赖关系无法被模拟,但是我的方法确实需要使用它。
另外,我是否应该避免我的单元测试甚至功能测试使用实际数据?比如说,我的测试是否应该永远不连接到数据库API来临时添加数据、操作和测试并在之后删除它?
3个回答

7
您说:
大多数时候,第三方依赖项无法进行模拟。
为什么?您总是可以为与第三方组件的交互定义接口,然后提供一个实现,该实现只需将每个调用委托给第三方组件,然后您就能够为测试提供此接口的模拟。
如果第三方组件具有大量API,则可能需要花费很多工作,但仍然值得这样做。
类似的项目存在于创建包装器以绕过.net文件系统类的测试中。
因此,您可以执行以下操作:
public interface IMyDependency
{
    public void SomeMethod();

    public int CaclateSomething();

    //add other methods that you will call in the 3rd party dependency
}

然后,您需要有一个包装器,只需委派给您正在使用的实际第三方组件,如下所示:
public class MyDependencyWrapper : IMyDependency
{
    private My3rdPartyDepency actualDependency;

    public MyDependencyWrapper(My3rdPartyDepency actualDependency)
    {
         this.actualDependency=actualDependency;
    }

    public void SomeMethod()
    {
        actualDependency.SomeMethod()l
    }

    public int CaclateSomething(string aParam)
    {
        return actualDependency.CalculateSomething(aParam);
    }

    //add other methods that you will call in the 3rd party dependency
}

现在您可以在测试中仅使用接口,因此可以编写不依赖于实际第三方组件的单元测试。

但是,那些接口的实现中的所有方法/过程都可以进行单元测试吗?还是我只需要在功能测试中担心这个问题? - Julious Igmen
感谢您扩展您的回答。此外,这里有一个与此相关的好问题:https://dev59.com/WVbUa4cB1Zd3GeqPDfVn?rq=1 - Julious Igmen

6

单元测试

你应该对所有进行测试。但不是所有都使用单元测试。单元测试不依赖于环境-数据库、网络连接等。处理不受信任/不稳定的第三方工具的最佳实践是在您的代码和第三方代码之间创建反腐层。因此,重构您的代码以使业务逻辑尽可能独立,并对业务逻辑进行单元测试。

如果您不确定第三方代码的工作方式或将来是否会更改,则可以进行“学习测试”。这些是单元测试(如果可能),它们断言您所依赖的行为。在学习测试中,您仅测试第三方代码,而不是您自己的代码。

如果第三方代码比较可信(知名的开放源代码库),则认为它有效,不要进行任何分离,而只对您的代码进行单元测试,而不对库进行测试。

非单元测试

如果您的测试需要外部环境(数据库、网络等),则应进行集成测试。它的目的不是测试业务逻辑,而是确保正确连接了所有部件。SQL测试是其中最著名的例外之一。

如何进行集成测试没有简单的规则(您可以写关于SQL测试的书)。它取决于您要测试什么,需要/想要多少与您的生产环境相似。例如,您可以对内存数据库或类似于生产环境的数据库(例如Oracle、Postgres等)进行SQL测试。但是,无论如何设计集成测试,您都必须确保每个测试都以已知的环境状态开始。并且您必须考虑留下环境处于脏状态的错误和此类测试的速度。


谢谢提到反腐层。现在我明白我要找什么了。 - Julious Igmen

3
一般来说,我们认为第三方软件已经过测试并且能够正常工作。但是当您发现一个bug时,它可能会让您感到惊讶。
这取决于您正在进行单元测试的内容。例如,访问某个奇特硬件或资源,或者只是简单的网络连接等一些东西,不应该进行单元测试。对于这些调用,我们使用mocks,并不对它们进行单元测试。
对于数据库,您可以使用mocks而不是真正的类来访问数据库。或者,您可以在单元测试设置方法中创建内存中的数据库,并在清理期间将其销毁。

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