gpt4 book ai didi

java - 模拟抽象类的非抽象方法

转载 作者:行者123 更新时间:2023-11-30 08:00:11 28 4
gpt4 key购买 nike

我正在尝试对扩展抽象基 class 的类进行单元测试。以下是用于说明目的的“相似类”:

public abstract class MyAbstractBaseClass {
@Autowired
private WaterFilter waterFilter;

protected List<String> filterComponents(List<String> allComponents) {
return waterFilter.filter(allComponents);
}
}

public class MyDerivedClass extends MyAbstractBaseClass {
public List<String> filterWater(List<String> allWaterComponents) {
List<String> filteredComponents = this.filterComponents(allWaterComponents); //calls abstract class's filterComponets()
filteredComponents.add("something-else");
return filteredComponents;
}
}

这是我正在尝试的单元测试:

    @RunWith(EasyMockRunner.class)
public class MyDerivedClassTest {
@TestSubject
private MyDerivedClassTest SUT;

@Before
public void setup() {
SUT = new MyDerivedClassTest();
}

@Test
public void test filterWater_HappyCase() {
//I want to mock my abstract class's filterComponents() method
//I am trying this:
EasyMock.expect(SUT.filterComponents(getDummyComponents())).andReturn(getSomeComponents());

//What to replay here?
//EasyMock.replay(...)

List<String> actualResult = SUT.filterWater(getDummyComponents());

//assert something
//What to verify?
//EasyMock.verify(...)
}
}

当我运行这个测试时,我得到了

java.lang.NullPointerException

MyAbstractBaseClass.filter(allComponents)

我知道 Autowiring 的“waterFilter”没有被初始化。但是,我只想在我的单元测试中模拟抽象 class 的“非抽象”方法。

我应该如何使用 EasyMock 来解决这个问题?另外,我不知道要replay()verify() 做什么。

最佳答案

当你写一个单元测试时,你测试一个对象(通常是它的一个方法),你可能会模拟一个对象(通常是它的一个方法)。
但是,你不应该对同一个对象进行单元测试和模拟,因为在某种程度上,这似乎不太自然:如果你测试一个类的方法,被测类的行为应该尽可能保持自然,而不是假装自己的方法。
否则,我们会怀疑单元测试的质量是否良好。
为什么 ?因为它不反射(reflect)我们在运行时将拥有的类的真实行为,而只是其行为的一部分。在单元测试中,研究了隔离,但其背后的想法是将被测类仅与其他类隔离,而不是隔离其自身的行为。
当然,您可以尝试在被测类的抽象类中模拟非抽象方法,但测试的设计和质量可能会变得不那么好。

在您的情况下,我想有两个原因可以模拟抽象类中的非抽象方法:

  • waterFilter 字段依赖性让您感到厌烦,因为它没有被赋值,因此在测试期间会引发异常 (NullPointerException)。
  • 你真的想模拟抽象类中的非抽象方法,因为你已经对这个方法进行了单元测试,你不想重复这个测试。

1) 如果您的问题是 waterFilter 字段依赖性。

您应该模拟 waterFilter 字段。要模拟一个字段,它必须是可访问和可修改的。在您的情况下,它不是直接的,因为该字段是私有(private)的。

因此,您可以通过两种方式访问​​它以模拟它:

  • 更改您的设计以提供从公共(public)方法或在 MyDerivedClass 的构造函数中设置字段的可能性。
  • 使用反射来设置字段(使用 API 或自己做,因为这并不难)。

您不需要使用 EasyMock 进行验证操作。只需模拟 waterFilter.filter(allComponents) 返回的结果,例如:

 waterFilterMock.filter(mockedComponents) 

通过这种方式,模拟返回您选择的值,并且在您的 JUnit 断言中,您能够为您的被测方法执行正确的断言。

仅供引用,您可以使用 Mockito 而不是 EasyMock。它更灵活,并提供更具可读性的操作。例如,您可以使用 Mockito 来完成:

Mockito.when(waterFilterMock.filter()).thenReturn(mockedComponents);

如您所见,它更具可读性。

2) 如果你的问题是你真的想模拟抽象类中的非抽象方法,因为你已经对它进行了单元测试

您应该修改您的设计并使用组合而不是继承。您将不再有 MyAbstractBaseClass,而只是两个类之间的依赖关系(一个具有另一个的字段)。这样,您就可以自然地模拟 filterComponents() 方法。

关于java - 模拟抽象类的非抽象方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38681748/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com