gpt4 book ai didi

java - 如何在 1 个测试类中使用相同的方法测试多个对象?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:21:09 26 4
gpt4 key购买 nike

我有 2 个不同的对象:C c 和 B b。 B 和 C 实现接口(interface) A,以便它们可以使用接口(interface) A 中存在的名为 color() 的方法。我已经对类 B 进行了单元测试,测试了 B 已实现的 color() 方法。所以我现在想做的是用 B 类的相同单元测试来测试 C 类中的 color() 方法。因此我想在为 B 类制作的同一个测试类中测试它们。

要实现这一点,我的一位 friend 说我必须利用这些类的并行类层次结构。但我真的不知道我应该如何在我的测试中实现它。

这是我的代码:

private static Sprites sprites;
private static B b;

@BeforeAll
static void setUp() {
sprites = mock(Sprites.class);
b = new B(sprites);
}

@Test
void testing_color_method() {

M m = mock(M.class);

b.color(m);

verify(sprites).getSpritesOf(m);

}

//... some more tests

我正在使用 JUnit 5,我知道我可以使用 @ParameterizedTest 在测试中注入(inject)对象 B 和 C,让它们使用相同的单元测试,我也对此进行了一些谷歌搜索,但没有搜索结果关于这种情况,需要在 1 个测试中注入(inject) 2 个对象。那么我应该如何重构代码,以便我可以注入(inject)类 B 和 C,让它们使用我已经为 B 编写的相同单元测试?

最佳答案

BC 使用相同的测试意味着,您实际上是通过接口(interface) A 进行测试。这些将主要是黑盒测试,因为您的测试只能依赖于接口(interface)的元素,而不是 BC 中特定实现的元素。下面详细介绍这一点。

但是,首先,一些示例代码如何实现您的目标:该方法使用使用 @MethodSource 的 Junit 5 参数化测试。在示例中,@MethodSource 提供作为参数 a) 测试的描述(在测试方法逻辑中未使用,因此在此处称为 dummy),b)实现接口(interface) A 的类之一的实例,并且,为了您可以尝试的工作示例,c) 对象的预期类名。

接口(interface)A的代码:

package so56386880;

public interface A {
public void color();
}

类 B 和 C 的代码(我使用相同的代码,这里显示 B):

package so56386880;

public class B implements A {
public void color() { }
}

测试代码

package so56386880;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

class A_Test {

@DisplayName("Test one common property of color method")
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("provideImplementors")
void color_whenCalled_shallXxx(String dummy, A someA, String expectedClassName) {
// you would do some test for someA.color(), but just for example:
assertEquals(expectedClassName, someA.getClass().getName());
}

static Stream<Arguments> provideImplementors() {
return Stream.of(
Arguments.of("expecting class B's name", new B(), "so56386880.B"),
Arguments.of("expecting class C's name", new C(), "so56386880.C"));
}

}

如上所述,这只能执行仅限于使用接口(interface) A 的测试。由于 BC 会有不同的实现,您可能还需要对 BC 进行一些特定的测试>。请记住,测试的目标是发现错误 - 不同的实现通常有不同的潜在错误(不同的控制流、不同的溢出可能性等)。

更新:上面的解决方案回答了如何使用提供被测类作为参数的参数化测试来实现。另一种方法是为接口(interface)实现一个测试类如下:

package so56386880;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

abstract class A_Test2 {

public abstract A getClassUnderTest();

@Test
void color_whenCalled_shallXxx() {
A classUnderTest = this.getClassUnderTest();
classUnderTest.color(); // exercise
assertEquals(expected..., actual...);
}
}

然后从中派生,如下所示:

package so56386880;

class B_Test extends A_Test2 {
public A getClassUnderTest() { return new B(); }
}

在 Junit 5 下运行 B_Test 时,将执行基类中的所有测试方法(如果在 B_Test 中定义,则加上其他方法)。优点是,无论何时创建新的派生类,您都不必修改 A_Test2。但是,如果每个派生类的预期值都不同(如第一个解决方案中的类名),则需要进行一些调整,例如更多类似于 getClassUnderTest 的回调方法。

关于java - 如何在 1 个测试类中使用相同的方法测试多个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56386880/

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