我有2个不同的对象:C c和B b。 B和C实现接口A,以便他们可以使用接口A中存在的称为color()的方法。我已经对类B进行了单元测试,以测试B已实现的color()方法。因此,我现在想做的是在C类中使用与B类相同的单元测试来测试color()方法。因此,我想在为B类创建的同一测试类中对它们进行测试。
要实现这一目标,我的一位朋友说我将不得不利用这些类的并行类层次结构。但是我真的不知道如何在测试中实现它。
这就是我所使用的代码:
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在测试中注入对象B和C,以使它们使用相同的单元测试,我也对此进行了一些google搜索,但是没有搜索结果关于这种情况,在1个测试中需要注入2个对象。那么,我应该如何重构代码,以便注入类B和C,让它们使用与我已经为B创建的单元测试相同的单元测试?
答案 0 :(得分:0)
对B
和C
使用相同的测试意味着实际上您正在通过接口A
进行测试。然后,这些将主要是黑盒测试,因为您的测试只能依赖于界面的元素,而不能依赖于B
和C
中特定实现的元素。有关此内容的更多信息。
但是,首先,提供一些示例代码来说明如何实现目标:该方法使用@MethodSource
进行的Junit 5参数化测试。在示例中,@MethodSource
提供了以下内容:a)测试的描述(在测试方法逻辑中未使用,因此在此称为dummy
),b)其中一个类的实例它实现了A
接口,并且,为了便于工作的示例,您可以尝试使用c)对象的预期类名。
接口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"));
}
}
如上所述,这只能执行仅限于使用接口A
的测试。由于B
和C
将具有不同的实现,因此您可能还需要针对B
和C
进行一些特定的测试。请记住,测试的目的是发现错误-不同的实现通常具有不同的潜在错误(不同的控制流,不同的溢出可能性等)。
更新:上面的解决方案回答了如何使用参数化测试来做到这一点,该测试将被测类作为参数。一种替代方法是为接口as below
实现测试类:
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
的回调方法。