单元测试工程化-测试代码也可以被依赖

181 阅读2分钟

文章内容前置说明:

  1. 框架:SpringBoot 2.4.4 , Spring Data JPA
  2. 使用的需求样例参考: 业务需求分析详解-如何精确识别并发问题

问题背景

假设在这样一个多模块项目中:

Pasted image 20230502223452.png

其依赖关系如下:

image.png

在不同的模块下通常会有一些测试代码,比如在domain模块下,有这样一段用于准备不同状态的Call实体的测试代码:

// domain的test目录下: com.peng.project.domain.entity.CallDomainPrepare
public class CallDomainPrepare {  
  
	public Call prepareCallingCall() {  
		// 返回一个处于Calling状态的呼叫实体
	}  
	  
	public void prepareBusyCall() {  
		// 返回一个处于Busy状态的呼叫实体
	}  
}

而在application模块下,有CallApplicationService,里面有一个call方法,如下所示:


@Service  
@RequiredArgsConstructor  
public class CallApplicationService {  
  
	private final CallDomainService callDomainService;  
  
	public Call call() {  
		return callDomainService.call();  
	}  

	public void cancelCall(UUID callId) {  
		// 执行一些前置的判断逻辑
		callDomainService.cancelCall(callId);  
	}
}

此时如果想要测试ApplicationService的cancelCall方法,则需要先创建一个处于呼叫状态的call对象。测试方法类似于这样:


class CallApplicationServiceTest extends BaseTest {  
  
	@Autowired  
	private CallApplicationService callApplicationService;  
	  
	@Autowired  
	private CallDomainService callDomainService;  
	  
	@Autowired  
	private TestUserFactory userFactory;  
	  
	@Test  
	@DisplayName("取消呼叫成功")  
	void should_cancel_call() {  
		Call call = callDomainService.call(  
						userFactory.createUser(),  
						userFactory.createUser(),  
						CallValues.builder().build());  
		callApplicationService.cancelCall(call.getId());  
	}  
}

可是我们已经在domain模块的test目录下已经有了一个CallDomainPrepare类,专门用于生成各种状态的Call对象了,而在CallApplicationService的测试中却不能复用这样的类。如果后续还要继续测试 呼叫正忙、呼叫连接失败、呼叫成功等场景,依然也需要前置地生成一个呼叫中的类。有没有什么办法可以引用到在被依赖模块domaintest目录下已经定义好的一些类呢?

解决方案

在maven的插件中,有一个插件叫maven-jar-plugin,可以在我们打包的时候把test目录也打成jar包。在pom文件中增加插件配置:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-jar-plugin</artifactId>
	<version>3.3.0</version>
	<executions>
		<execution>
			<goals>
				<goal>test-jar</goal>
			</goals>
		</execution>
	</executions>
</plugin>

然后执行mvn verify命令,最终的打包产物有两个,一个是源代码jar,另一个则是test-jar,如图所示:

Pasted image 20230502233653.png

然后我们只需要在application模块中引入test模块即可,注意这里的引入有些不同:

<dependency>
	<groupId>com.peng.project</groupId>
	<artifactId>domain</artifactId>
	<version>1.0.0</version>
	<type>test-jar</type>
	<scope>test</scope>
</dependency>

需要在引入的时候指定typetest-jar,这样就可以在application的test中引用到模块中的test目录定义好的类了。最终效果如下所示:


	@Autowired  
	private CallDomainPrepare callDomainPrepare;
	
	@Test
    @DisplayName("取消呼叫成功")
    void should_cancel_call() {
//        Call call = callDomainService.call(
//                userFactory.createUser(),
//                userFactory.createUser(),
//                CallValues.builder()
//                        .build());
        Call call = callDomainPrepare.prepareCallingCall(CallValues.builder().build());
        callApplicationService.cancelCall(call.getId());
    }

而在CallDomainPrepare中的实现则是:


// com.peng.project.domain.entity.CallDomainPrepare

	@Autowired
    private TestUserFactory userFactory;

    public Call prepareCallingCall(CallValues callValues) {
        User fromUser = userFactory.createUser();
        User targetUser = userFactory.createUser();
        return callDomainService.call(fromUser, targetUser, callValues);
    }

这么做可以让在测试目录下定义的一些类都可以被复用到,不用再重复创建一遍。在多模块的项目中非常有用,可以加快测试代码编写的速度。