假设您有以下要测试的课程:
public class SomeService {
public String someMethod(SomeEntity someEntity) {
return someEntity.getSomeProperty();
}
}
SomeEntity看起来像这样:
public class SomeEntity {
private String someProperty;
public getSomeProperty() {
return this.someProperty;
}
}
您想要做的断言如下:
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
如何使此测试工作?
1)为某些属性添加一个setter'在SomeEntity类中。我不认为这是一个很好的解决方案,因为您不会更改生产代码以使测试有效。
2)使用ReflectionUtils设置此字段的值。测试看起来像这样:
public class TestClass {
private SomeService someService;
@Test
public void testSomeProperty() {
SomeEntity someEntity = new SomeEntity();
ReflectionTestUtils.setField(someEntity, "someProperty", "someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
}
3)在测试类中创建一个扩展SomeEntity类的内部类,并为该字段添加setter。但是,要实现此功能,您还需要更改SomeEntity类,因为该字段应该变为“受保护”字样。而不是私人'。测试类可能如下所示:
public class TestClass {
private SomeService someService;
@Test
public void testSomeProperty() {
SomeEntityWithSetters someEntity = new SomeEntityTestWithSetters();
someEntity.setSomeProperty("someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
public class SomeEntityWithSetters extends SomeEntity {
public setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
}
}
4)你使用Mockito来模拟SomeEntity。如果您只需要在类中仅模拟一个属性,那么似乎很好,但如果您需要像10个属性那样进行模拟,那该怎么办呢。测试可能如下所示:
public class TestClass {
private SomeService someService;
@Test
public void testSomeProperty() {
SomeEntity someEntity = mock(SomeEntity.class);
when(someEntity.getSomeProperty()).thenReturn("someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
}
答案 0 :(得分:7)
您可以使用反射设置值。它不需要对生产代码进行任何更改。
ReflectionTestUtils.setField(YourClass.class,“fieldName”,fieldValue);
答案 1 :(得分:2)
您可以添加具有默认(包私有)范围的setter。
答案 2 :(得分:0)
使用SomeService.someMethod()的junit测试
替代1.不应该使用它,因为不需要更改实体来编写junit。
替代2.可以使用。
替代3.同样一个3,不需要为junit延伸。如何无法延长班级。
替代4.是的,一个不错的选择。因为同样的原因,使用了mockito。
答案 3 :(得分:0)
特定于SomeService
的行为/合同是可测试的?根据您的骨架代码,确实没有。它会在坏输入上抛出一个NPE,或者返回一个可能为null但可能不为null的String,具体取决于Hibernate魔法。不确定你实际可以测试。
答案 4 :(得分:0)
我之前经历过很多次这样的困境,一个快速的解决方案是让你想要模拟包受保护的字段,或者提供受保护的setter。当然两者都会改变生产代码。
或者,您可以考虑依赖注入框架,例如Dagger。以下是他们给出的一个例子:
@Module
class DripCoffeeModule {
@Provides Heater provideHeater(Executor executor) {
return new CpuHeater(executor);
}
}
此JUnit测试使用Mockito中的模拟对象覆盖DripCoffeeModule对Heater的绑定。模拟器被注入到CoffeeMaker中并进入测试阶段。
public class CoffeeMakerTest {
@Inject CoffeeMaker coffeeMaker;
@Inject Heater heater;
@Before public void setUp() {
ObjectGraph.create(new TestModule()).inject(this);
}
@Module(
includes = DripCoffeeModule.class,
injects = CoffeeMakerTest.class,
overrides = true
)
static class TestModule {
@Provides @Singleton Heater provideHeater() {
return Mockito.mock(Heater.class);
}
}
@Test public void testHeaterIsTurnedOnAndThenOff() {
Mockito.when(heater.isHot()).thenReturn(true);
coffeeMaker.brew();
Mockito.verify(heater, Mockito.times(1)).on();
Mockito.verify(heater, Mockito.times(1)).off();
}
}