猿问

在单元测试中避免外部输入

我想对 a 进行单元测试class A。这个类与其他类级联,所以class A创建了一个实例class B和class B的class C。像那样:


public class A {

    public B b;

    public A() {

        this.b = new B();

    }

}

 

public class B {

    public C c;

    public B() {

        this.c = new C();

    }

}

 

如果现在类 C 在其构造函数中读取任何外部输入,如文件或属性,我如何避免这种情况?我看不出你会如何模拟它,但是在测试时是否也有可能将外部因素排除在其他类之外?


慕无忌1623718
浏览 147回答 4
4回答

心有法竹

您在这里遇到的问题是您的类与其他类的特定实现紧密耦合,因此您的“单元”被迫一起测试所有这些类的行为。避免这种情况的典型方法是使用依赖注入,使您的类与接口而不是特定类耦合。然后您可以模拟注入的接口以对单个类的行为进行单元测试。public class AImpl {    public B b;    public AImpl(B b) {        this.b = b;    }}public interface B {    // methods}public class BImpl implements B {    public C c;    public BImpl (C c) {        this.c = c;    }}当您创建AImpl生产代码时,您现在必须为其提供特定的C实现。您可以这样做new AImpl(new BImpl(new CImpl)),也可以使用像 Spring 这样的依赖注入框架来为您计算出所有这些细节。B当您进行单元测试时,您可以创建一个模拟或存根以具有您希望为该特定测试展示的行为,并将该存根传递给构造函数: new AImpl(myMockedB)。

慕丝7291255

B您不应该在类中创建实例A- 相反,您应该B在创建时提供实例A- 它称为Inversion of Control。流行的方法是使用依赖注入,例如使用 Spring 框架。然后一切都变得简单 - 当您的类需要读取带有类的文件时FileReader,为了测试您可以创建一个“假”实现,例如当您调用时FileReader.readFile(),您的假实现将简单地返回硬编码字符串或流,具体取决于您想要什么。这个概念真的很大,想象一下当你FileReader实际上是一个DatabaseReaderor ExternalServiceCaller。不是在单元测试中测试真实的数据库(祝你好运),而是创建一个FakeDatabaseReader在常规 Java 上运行的数据库HashMap,一切都很容易测试。或者当您的代码处理时间/日期时,想象一个功能只在29th February- 您可以等待 4 年来测试它,或者为Clock您的测试提供一个设置为特定日期的对象。该类Clock具有提供各种替代时钟的静态方法,以提供固定时刻、调整到未来或过去的时刻,或具有改变节奏的时钟。

潇湘沐

首先,由于您不能注入 B 类,因此所有此类都不是为了进行温和测试而设计的,请注意,由于您将任何新内容添加到类中,这与对实例进行硬编码非常相似。适当的方式应该是  public class A {    public B b;    public A(B b) {        this.b = b;    }}请注意,您可以通过这种方式实例化类A a = new A(b); 这样,b 可以是模拟或虚拟或存根或任何用于测试目的的对象。如果您面临遗留代码,您应该重构它以使其能够被测试。如果这是您的设计,您应该尽快重构以使其可测试。控制反转和依赖注入应该有助于归档你想做的事情。

慕尼黑5688855

不是我知道的,你会处理这些外部因素,或者在 A、B 或 C 类本身的开发过程中确保在测试过程中不会出现此类问题。但是,如果您无法控制 A、B 或 C 类源,那么我认为您被卡住了!
随时随地看视频慕课网APP

相关分类

Java
我要回答