zoukankan      html  css  js  c++  java
  • springboot基于junit4的单元测试实践

    本ut的实践,未不需要加载过多的springbean,除了需要测试的方法,其他均是mock的。这样大大提高了启动测试的时间,但是编写mock,也同样需要大量的时间。所有我们只对于复杂业务写了单元测试,下面为代码实现

    import org.apache.commons.io.FileUtils;
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Type;
    import java.nio.charset.Charset;
    
    //将bean的数据,数据结果放在文件中,json格式加载出来 @RunWith(SpringRunner.
    class) public class MockBaseTest { private final static Logger LOGGER = LoggerFactory.getLogger(MockBaseTest.class);/** * * @param path commond json 文件路径 * @param clazz commond 类 * @return */ @SuppressWarnings("unchecked") public static <T> T loadObject(String path,Class<T> clazz){ String basePath = MockBaseTest.class.getResource("/").getPath(); String commandStr = null; try { commandStr = FileUtils.readFileToString(new File(basePath + path), Charset.defaultCharset()); return JsonHelper.fromJson(commandStr,clazz); } catch (IOException e) { LOGGER.error("loadCommand",e); } return null; } public static <T> T loadObject(String path, Type typeOfT){ String basePath = MockBaseTest.class.getResource("/").getPath(); try { String commandStr = FileUtils.readFileToString(new File(basePath + path), Charset.defaultCharset()); return JsonHelper.fromJson(commandStr,typeOfT); } catch (IOException e) { LOGGER.error("loadCommand",e); } return null; } }
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.TestConfiguration;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Import;
    import org.springframework.context.annotation.Lazy;
    
    //TestServiceImpl里所有的需要注入的bean都要mock,为了实际test代码地方简介一点,这里提个base类
    @Import(TestServiceBaseTest.BeanConfiguration.class)
    public class TestServiceBaseTest extends MockBaseTest {
        @Autowired
        public TestService testService;
    
        @TestConfiguration
        static class BeanConfiguration {
            @Bean
            public TestService testService() {
                return new TestServiceImpl();
            }
        }
    
        //------------------------------------------- bean ------------------------------------------------------------------------
        @MockBean
        public AaService aaService;
        @MockBean
        public BbService bbService;
        @MockBean
        public CcDao CcDao;
    
    
    }
    import com.google.common.cache.Cache;
    import com.google.common.cache.CacheBuilder;
    import com.google.gson.reflect.TypeToken;
    import org.junit.Assert;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.rules.ExpectedException;
    
    import java.math.BigDecimal;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    import static org.mockito.AdditionalMatchers.not;
    import static org.mockito.ArgumentMatchers.*;
    import static org.mockito.Mockito.*;
    
    
    public class TestServicePayLockTest extends TestServiceBaseTest {
        @Rule
        public ExpectedException expectedException = ExpectedException.none();
    
        private static Long LOCK_SECONDS = 5L;
    
    //替代redis,可过期功能
    private Cache<String, String> cache = CacheBuilder.newBuilder() .expireAfterWrite(LOCK_SECONDS, TimeUnit.SECONDS) .build();
    //需要往数据库插入数据,并get时,这个可替代数据库功能,本次下面代码没有使用
    private List<Test> dataList = new ArrayList(); @Test
    public void payLockAmountError() { expectedException.expect(RuntimeErrorException.class); expectedException.expectMessage("数据发生变化,请刷新重试!"); TypeToken<PayLock> typeToken = new TypeToken<PayLock>() { }; String number = "1"; BigDecimal amount = new BigDecimal("100.1"); PayLock payLock = loadResource("command/payment/test_data.json", typeToken.getType()); when(ccDao.find(anyString())) .thenReturn(payLock.orders); when(ccDao.find2(anyList())).thenReturn(payLock.items); setRedicLockMock(); testService.payLock(number, amount); } @Test public void payLockFailError() throws InterruptedException { TypeToken<PayLock> typeToken = new TypeToken<PayLock>() { }; String number = "1"; BigDecimal amount = new BigDecimal("6"); PayLock payLock = loadResource("command/payment/test_data.json", typeToken.getType()); when(ccDao.find(eq("1"))).thenReturn(payLock.orders); when(ccDao.find(not(eq("1")))).thenReturn(payLock.orders2); setRedicLockMock(); when(ccDao.find2(anyList())).thenReturn(payLock.items); testService.payLock(number, amount); try { testService.payLock("2", amount); } catch (Exception e) { Assert.assertEquals(e.getClass(), RuntimeException.class); Assert.assertEquals(e.getMessage(), "数据被锁定,请稍后刷新重试!"); } Assert.assertEquals(3, cache.size()); Thread.sleep(1000 * LOCK_SECONDS); testService.payLock("2", amount); } @Test public void payLockReleaseError() { expectedException.expect(RuntimeException.class); expectedException.expectMessage("数据被锁定,请稍后刷新重试!"); TypeToken<PayLock> typeToken = new TypeToken<PayLock>() { }; String number = "1"; BigDecimal amount = new BigDecimal("6"); PayLock payLock = loadResource("command/payment/test_data.json", typeToken.getType()); when(ccDao.find(anyString())).thenReturn(payLock.orders); when(redisLockUtil.getLock(not(eq(PayCode.PAY_LOCK + "3")), anyString(), eq(PayCode.LOCK_TIME), eq(PayCode.LOCK_TIME_UNIT))).thenReturn(true); when(redisLockUtil.getLock(eq(PayCode.PAY_LOCK + "3"), anyString(), eq(PayCode.LOCK_TIME), eq(PayCode.LOCK_TIME_UNIT))).thenReturn(false); doThrow(new RuntimeException("锁释放失败!")).when(redisLockUtil).releaseLock(eq("2"), anyString()); when(ccDao.find2(anyList())).thenReturn(payLock.items); testService.payLock(number, amount); } private void setRedicLockMock() {
    //when invoke return method,do something when(redisLockUtil.getLock(anyString(), anyString(), anyLong(), any(TimeUnit.class))).then((a)
    -> { String key = a.getArgument(0); String value = cache.getIfPresent(key); if (value == null) { cache.put(key, a.getArgument(1)); return true; } return false; });
    //when invoke viod method,do something doAnswer(answer
    -> { String ifPresent = cache.getIfPresent(answer.getArgument(0)); if (ifPresent != null && ifPresent.equals(answer.getArgument(1))) { cache.invalidate(answer.getArgument(0)); } else if(ifPresent != null && ifPresent(answer.getArgument(0))){
              throw new RuntimeExcetion("锁释放失败!");
           }
    return null; }).when(redisLockUtil).releaseLock(anyString(), anyString()); } // 本次ut需要所有的对象,这里构建一个内部类,有用加载json文件里的配置 class PayLock { List<Order> orders; List<Order> orders2; List<Item> items; } }
  • 相关阅读:
    IOS:接口返回包含转义字符去掉转义字符
    properties和yml进行对比
    IDEA安装插件时搜索不到,一直在转圈刷新,无法安装
    VMware 15 虚拟机黑屏问题
    扩容根分区
    CentOS 6 各种启动文件损坏及修复
    RabbitMQ面试题
    FTP,SFTP服务器登录权限和根目录的设置
    Tee命令的几个使用实例
    ssh-copy-id 后无法免密登录
  • 原文地址:https://www.cnblogs.com/jaxlove-it/p/15314602.html
Copyright © 2011-2022 走看看