如何测试服务或正确模拟? Java11, Spock 框架
How to test a service or do it right mock? Java11, Spock Framework
各位同仁,欢迎大家!告诉我如何决定,或如何行动。 (Java11, SpringBoot, testing - Spock Framework) 我需要编写一个测试 class 方法的测试,整个问题是被测 class 的方法调用了另一个服务通过继承,它不是在被测 class 中声明的,而是在其抽象祖先中声明的。如何测试这样的故事?如果这个服务是在测试本身的 class 中声明的,那么一切都很清楚,我会在测试中创建一个模拟并将它传递给构造函数,但是如果这个服务位于祖先怎么办?我在下面附上示例代码。
// The class to be tested
@Service
public class ServiceForTest extends AbstractComponent{
public String methodForTest (String s) {
return someService.generateString(s);
}
}
//An abstract class from which the tested one is inherited and which contains the service
public class AbstractComponent {
@Autowired
protected SomeService someService;
}
public interface SomeService {
String generateString(String s);
}
@Service
public class SomeServiceImpl implements SomeService{
@Override
public String generateString(String s) {
return s;
}
}
下面是一个示例,说明如果服务在 class 正在测试中我会做什么
//TestClass
@Service
public class ServiceForTest extends AbstractComponent{
final SomeService someService;
public ServiceForTest(SomeService someService) {
this.someService = someService;
}
public String methodForTest (String s) {
return someService.generateString(s);
}
}
class 测试 groovy, Spock 框架
class ServiceForTestTest extends Specification {
ServiceForTest serviceForTest
void setup(){
SomeService someServiceMock = Mock(SomeService)
someServiceMock.generateString("TEST") >> "TEST"
serviceForTest = new ServiceForTest(someServiceMock)
}
def "Test for return current value"(){
when:
def methodForTest = serviceForTest.methodForTest("TEST")
then:
methodForTest == "TEST"
}
}
您使用 @Autowired
,即某种依赖注入框架,例如 Spring 或 Java EE CDI。这些框架有测试支持。 Spock 专门针对 Spring 测试提供了一个 Spring module 供您使用。我不是 Spring 用户,所以我不能告诉你具体怎么做,但是文档非常好。
作为一般性答案,即使没有任何框架支持,您也可以轻松地进行测试,只要您按照惯例将测试放入与被测 class 相同的包中。因为您要向其中注入模拟的字段是 protected
,所以对于 JVM 来说,所有子 classes 以及同一包中的其他 classes 都可以访问它。即,您可以简单地设置值:
serviceForTest = new ServiceForTest()
serviceForTest.someService = someServiceMock
或者,更优雅地使用隐式设置字段值的 Groovy-style 构造函数:
serviceForTest = new ServiceForTest(someService: someServiceMock)
一般来说,我推荐构造函数或 setter 注入而不是依赖字段注入(尤其是当字段是私有的时候),因为那样的话在可测试性方面你对你的 DI 框架有严格的依赖并且不容易写单元测试。所以如果你能重构,我建议你去做。您刚刚注意到,测试这些东西可能有点令人头疼,除非您有像在受保护字段的这种特殊情况下那样的出路。但这不是那么超级refactoring-friendly.
各位同仁,欢迎大家!告诉我如何决定,或如何行动。 (Java11, SpringBoot, testing - Spock Framework) 我需要编写一个测试 class 方法的测试,整个问题是被测 class 的方法调用了另一个服务通过继承,它不是在被测 class 中声明的,而是在其抽象祖先中声明的。如何测试这样的故事?如果这个服务是在测试本身的 class 中声明的,那么一切都很清楚,我会在测试中创建一个模拟并将它传递给构造函数,但是如果这个服务位于祖先怎么办?我在下面附上示例代码。
// The class to be tested
@Service
public class ServiceForTest extends AbstractComponent{
public String methodForTest (String s) {
return someService.generateString(s);
}
}
//An abstract class from which the tested one is inherited and which contains the service
public class AbstractComponent {
@Autowired
protected SomeService someService;
}
public interface SomeService {
String generateString(String s);
}
@Service
public class SomeServiceImpl implements SomeService{
@Override
public String generateString(String s) {
return s;
}
}
下面是一个示例,说明如果服务在 class 正在测试中我会做什么
//TestClass
@Service
public class ServiceForTest extends AbstractComponent{
final SomeService someService;
public ServiceForTest(SomeService someService) {
this.someService = someService;
}
public String methodForTest (String s) {
return someService.generateString(s);
}
}
class 测试 groovy, Spock 框架
class ServiceForTestTest extends Specification {
ServiceForTest serviceForTest
void setup(){
SomeService someServiceMock = Mock(SomeService)
someServiceMock.generateString("TEST") >> "TEST"
serviceForTest = new ServiceForTest(someServiceMock)
}
def "Test for return current value"(){
when:
def methodForTest = serviceForTest.methodForTest("TEST")
then:
methodForTest == "TEST"
}
}
您使用 @Autowired
,即某种依赖注入框架,例如 Spring 或 Java EE CDI。这些框架有测试支持。 Spock 专门针对 Spring 测试提供了一个 Spring module 供您使用。我不是 Spring 用户,所以我不能告诉你具体怎么做,但是文档非常好。
作为一般性答案,即使没有任何框架支持,您也可以轻松地进行测试,只要您按照惯例将测试放入与被测 class 相同的包中。因为您要向其中注入模拟的字段是 protected
,所以对于 JVM 来说,所有子 classes 以及同一包中的其他 classes 都可以访问它。即,您可以简单地设置值:
serviceForTest = new ServiceForTest()
serviceForTest.someService = someServiceMock
或者,更优雅地使用隐式设置字段值的 Groovy-style 构造函数:
serviceForTest = new ServiceForTest(someService: someServiceMock)
一般来说,我推荐构造函数或 setter 注入而不是依赖字段注入(尤其是当字段是私有的时候),因为那样的话在可测试性方面你对你的 DI 框架有严格的依赖并且不容易写单元测试。所以如果你能重构,我建议你去做。您刚刚注意到,测试这些东西可能有点令人头疼,除非您有像在受保护字段的这种特殊情况下那样的出路。但这不是那么超级refactoring-friendly.