当前位置:网站首页>Two schemes of unit test
Two schemes of unit test
2022-07-07 09:00:00 【bboyzqh】
principle
unit testing FIRST The principles are as follows
- Fast (fast): Unit tests should be run quickly , Otherwise, it will cost a lot of development / Deployment time .
- Isolation (isolated): Different test cases are isolated . One test does not rely on another test .
- repeatable (repeatable): Unit tests are repeatable , And when running repeatedly , Unit tests always give the same results ( The system environment is irrelevant ).
- Self verification (self-validating): Unit tests can verify their results , When they all pass , Give a simple “OK” The report , When they fail , You need to output concise details .
- In time (timely): Programmers before the code goes online , They should be written in time , To prevent bug.
Junit+Mockito+H2 database
The overall idea is to serve two parties API、 Configuration data are mock The way , Use a combination of H2 Memory database to initialize data to achieve the purpose of unit testing .
Two party service API use mock The way
To reduce unit test execution time , Need to remove two-party Services api And with mock Object substitution ,api mock The way is usually in Spring At startup mock Inject , namely mock Object replaces the real object . Here you can use Spring Self contained @TestExecutionListeners Annotation to unify mock Second party services api, The execution steps are as follows :
- establish TestContextManager
- Execute each one in turn AbstractTestExecutionListener Example of beforeTestClass Method
- Execute each one in turn AbstractTestExecutionListener Example of prepareTestInstance Method
- Spring Load and parse XML, In this process BeanFactoryPostProcessor
- When executing a test method , Execute each one in turn AbstractTestExecutionListener Example of beforeTestMethod Method
- Perform test methods
- Execute each one in turn AbstractTestExecutionListener Example of afterTestMethod Method
In the above way, press @Mock The objects marked by annotations can be unified mock, Do not load the external environment , Keep the environment isolated 、 The unit test runs fast . The detailed code is as follows :
public class MockitoBeansPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<Class<?>, MockitoBeansTestExecutionListener.MockBeanWrapper> allMockBeans = MockitoBeansTestExecutionListener.resolvedAllMockBeans();
for (Map.Entry<Class<?>, MockitoBeansTestExecutionListener.MockBeanWrapper> mockBeanWrapperEntry : allMockBeans.entrySet()) {
beanFactory.registerResolvableDependency(mockBeanWrapperEntry.getKey(), mockBeanWrapperEntry.getValue().getMockObject());
beanFactory.registerSingleton(mockBeanWrapperEntry.getValue().getBeanName(), mockBeanWrapperEntry.getValue().getMockObject());
}
}
}
public class MockitoBeansTestExecutionListener extends DependencyInjectionTestExecutionListener {
private static Map<Class<?>, MockBeanWrapper> mockBeans = new ConcurrentHashMap<>();
private static Map<Class<?>, List<Field>> injectMockBeans = new ConcurrentHashMap<>();
private static boolean hasInitialized = false;
public static Map<Class<?>, MockBeanWrapper> resolvedAllMockBeans() {
Assert.isTrue(hasInitialized);
return Collections.unmodifiableMap(mockBeans);
}
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
Field[] declaredFields = testContext.getTestClass().getDeclaredFields();
// Get the parent class Mock Method
Field[] superClassFields = testContext.getTestClass().getSuperclass().getDeclaredFields();
List<Field> mockFields = Lists.newArrayList(declaredFields);
if (superClassFields.length > 0) {
mockFields.addAll(Lists.newArrayList(superClassFields));
}
// Will need mock The object is created
for (Field field : mockFields) {
Mock mockAnnon = field.getAnnotation(Mock.class);
if (mockAnnon != null) {
field.setAccessible(true);
MockBeanWrapper wrapper = new MockBeanWrapper();
Class<?> type = field.getType();
wrapper.setMockObject(Mockito.mock(type));
wrapper.setBeanType(type);
wrapper.setBeanName(StringUtils.isEmpty(mockAnnon.value()) ? field.getName() : mockAnnon.value());
mockBeans.putIfAbsent(wrapper.getBeanType(), wrapper);
injectMockBeans.compute(testContext.getTestClass(), (targetClass, waitInjectFields) -> {
if (waitInjectFields == null) {
waitInjectFields = new ArrayList<>();
}
waitInjectFields.add(field);
return waitInjectFields;
});
}
}
hasInitialized = true;
}
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
Object testInstance = testContext.getTestInstance();
List<Field> fields = injectMockBeans.get(testContext.getTestClass());
if (fields != null) {
for (Field field : fields) {
field.setAccessible(true);
field.set(testInstance, mockBeans.get(field.getType()).getMockObject());
}
}
}
@Data
public class MockBeanWrapper {
private String beanName;
private Class<?> beanType;
private Object mockObject;
}
}
// Unit test base class
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:promotion/config/application-unittest.xml"})
@TestExecutionListeners({MockitoBeansTestExecutionListener.class,
TransactionalTestExecutionListener.class,
SqlScriptsTestExecutionListener.class})
public abstract class AbstractTest {
@Mock
protected LogisticService logisticService;
@Mock
protected ItemBatchSpecService itemBatchSpecService;
//......
}
H2 Data initialization of memory database
H2 Database is an embedded memory database , Its grammar and MySQL The grammar is very close to , It is very suitable for unit test data preparation scenarios . So we need to achieve The data in the charge of this application directly depends on H2 Database storage , A single use case uses [email protected] Annotations prepare data separately , That is, the responsible method is not applied mock, From the upper layer to the real database call . The detailed configuration is as follows :
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:common/common_schema.sql"/>
</jdbc:embedded-database>
<bean id="h2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:common/mybatis-config.xml"/>
<property name="mapperLocations">
<list>
<value>classpath:mapper/brule/Promotion*.xml</value>
</list>
</property>
</bean>
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yt.smc.dal.flashbuy.mapper,com.yt.smc.dal.brule.mapper"/>
<property name="sqlSessionFactoryBeanName" value="h2SqlSessionFactory"/>
</bean>
Unit test examples
The unit test class only needs to inherit the unit test base class AbstractTest that will do , The sample code is as follows :
public class NoBatchPlaceOrderTest extends AbstractTest {
@Autowired
private TradeService tradeService;
@Sql("classpath:promotion/db/trade/placeorder/nobatch_place_order_01.sql")
@Test
public void testplaceOrderFinishTest1() {
Mockito.when(itemPriceService.skuPrice(any())).thenReturn(getNoBatchSkuPriceMap());
SmcResultData<List<CouponOwnerShareDTO>> smcResultData = new SmcResultData<>();
smcResultData.setData(Lists.newArrayList());
Mockito.when(couponTradeService.shareCouponOwner(any(), any())).thenReturn(smcResultData);
SmcResultData<PaceOrderFinishReDTO> paceOrderFinishResult = new SmcResultData<>();
PaceOrderFinishReDTO paceOrderFinishReDTO = new PaceOrderFinishReDTO();
paceOrderFinishResult.setData(paceOrderFinishReDTO);
Mockito.when(promotionPlaceExecuteService.placeOrderFinishPromotion(any(), any())).thenReturn(paceOrderFinishResult);
Mockito.when(itemSqueryAdapter.listItemByIds(Mockito.any())).thenReturn(getItemDetailList());
PlaceOrderRequestDTO requestDTO = buildPlaceOrderRequest1();
PlaceOrderResponseDTO responseDTO = tradeService.placeOrderFinish(requestDTO);
System.out.println(JSON.toJSONString(responseDTO));
Assert.assertNotNull(responseDTO);
Assert.assertEquals(1, responseDTO.getPromotionPlaceOrderDTOS().size());
Assert.assertEquals(16900, responseDTO.getPromotionPlaceOrderDTOS().get(0).getOrderPrice().longValue());
Assert.assertEquals(1, responseDTO.getPromotionPlaceOrderDTOS().get(0).getPromotionPlaceActivityDTOs().size());
Assert.assertEquals(3000, responseDTO.getPromotionPlaceOrderDTOS().get(0).getPromotionPlaceActivityDTOs().get(0).getActivityCreatePrice().longValue());
}
Spock+Mockito+H2 database
use Spock Their ideas are basically the same Juit Think the same , The difference is in using groovy Language for writing unit tests . Use groovy Conduct unit testing based on behavior driven development (BDD) Thought , During unit testing, use cases need to be mapped to given、when and then, And Junit Compared with this way, it is closer to business expression . First, introduce dependencies as follows ( Pay attention to the matching version , Inconsistent versions may cause unit tests to fail ):
<!--Spock The test framework -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.3-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.4</version>
</dependency>
Based on the above mock Idea creation AbstractSpockTest Base class , as follows :
@ContextConfiguration(locations = "classpath:promotion/config/application-unittest.xml")
@TestExecutionListeners([
MockitoBeansTestExecutionListener.class,
TransactionalTestExecutionListener.class,
SqlScriptsTestExecutionListener.class
])
abstract class AbstractSpockTest extends Specification {
@Mock
protected ItemBatchSpecService itemBatchSpecService;
//......
}
Examples of unit tests are as follows :
class UserTaskServiceSpockTest extends AbstractSpockMockTest {
@Autowired
private UserTaskService userTaskService;
@Sql("classpath:db/share/query_share_detail_info.sql")
@Unroll
def " The shared person scans the sharing code details unit test "() {
given:
Mockito.when(activityService.checkActivityById(any(), any())).thenReturn(getCheckReturnResult())
Mockito.when(activityService.checkUser(any(), any(), any())).thenReturn(getCheckReturnResult())
Mockito.when(iSnsUserServiceWrapper.getSnsUserById(any())).thenReturn(getSnsTaoBaoUserDTO())
ShareDetailQueryRequest shareDetailQueryRequest = new ShareDetailQueryRequest(shareCode: shareCode, userId: userId)
expect:
ServiceResult<ScanShareResultVO> result = userTaskService.queryShareDetailInfo(shareDetailQueryRequest)
result.getData().getSelf() == self
result.getData().getSourceUserId() == sourceUserId
where:
shareCode | userId | self | sourceUserId
"da0f4a99c41ff8cc3634830552239c8fb5503076ab" | 3L | false | 5L
"da0f4a99c41ff8cc3634830552239c899e683076ab" | 4L | true | 5L
}
}
summary
The principles of the two implementation methods are the same , In terms of style "Spock+Mockito+H2 database " This method has less code 、 Closer to business expression , recommend !
边栏推荐
- Greenplum 6.x monitoring software setup
- Alibaba P8 teaches you how to realize multithreading in automated testing? Hurry up and stop
- LeetCode 715. Range 模块
- Esp32-ulp coprocessor low power mode RTC GPIO interrupt wake up
- GoLand set goproxy
- Recommended by Alibaba P8, the test coverage tool - Jacobo is very practical
- Panel display technology: LCD and OLED
- selenium自动化集成,八年测试经验软测工程师,一篇文章带你学懂
- Opencv converts 16 bit image data to 8 bits and 8 to 16
- Golang etcdv3 reports an error. The attribute in grpc does not exist
猜你喜欢
面试题:高速PCB一般布局、布线原则
ESP32-ULP协处理器低功耗模式RTC GPIO中断唤醒
JS operation
Druid monitoring - Introduction to JMX usage and principle
Lenovo hybrid cloud Lenovo xcloud: 4 major product lines +it service portal
Expérience de port série - simple réception et réception de données
阿里p8推荐,测试覆盖率工具—Jacoco,实用性极佳
Output all composite numbers between 6 and 1000
LeetCode 715. Range 模块
Troublesome problem of image resizing when using typora to edit markdown to upload CSDN
随机推荐
Calculation s=1+12+123+1234+12345 C language
徽商期货公司评级是多少?开户安全吗?我想开户,可以吗?
OpenGL三维图形绘制
【istio简介、架构、组件】
Greenplum 6.x common statements
C语言指针(上篇)
GoLand set goproxy
【Istio Network CRD VirtualService、Envoyfilter】
C语言指针(特别篇)
寄存器地址名映射
On December 8th, 2020, the memory of marketing MRC application suddenly increased, resulting in system oom
Frequently Asked Coding Problems
LED模拟与数字调光
Serial port experiment - simple data sending and receiving
年薪50w阿裏P8親自下場,教你如何從測試進階
串口实验——简单数据收发
硬件大熊原创合集(2022/06更新)
Simulation volume leetcode [general] 1706 Where does the ball meet
Unityshader introduction essentials personal summary -- Basic chapter (I)
Simulation volume leetcode [general] 1609 Parity tree