zoukankan      html  css  js  c++  java
  • Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock

    在前面的文章中(Spring Boot 2 实践记录之 Powermock 和 SpringBootTest)提到了使用 Powermock 结合 SpringBootTest、WebMvcTest 来 Mock Service、Controller 中的 静态类和静态方法。

    但此法有两个弊端,一是这样的单元测试运行速度慢,二是时不时会出现测试运行停顿的情况。

    一个可选的方案就是将这些用在 Service、Controller 中的静态类和静态方法的引用,封装在普通 Bean 中,Service、Controller 使用这些 Bean 来完成相应的功能。这样一来,针对 Service、Controller 的单元测试中,就可以使用 @MockBean 结合 Mockito 直接 Mock 这些封装类及其方法了。

    例如,在用户注册中,使用了 UUID 类来生成 用户id,使用 Date 插入注册时间,代码如下:

    @Service
    public class UsersServiceImpl implements UsersServiceInterface {
    
        @Autowired
        private Users users;
    
        @Autowired
        private UsersMapper usersMapper;
    
        /**
         * 用户注册 service 方法
         * @param userIn
         * @return
         */
        @Override
        public String signUp(UserIn userIn) {
            String result;
            Date now = new Date();
            users.setUserId(UUID.randomUUID().toString());
            users.setRegTime(now);
            ......
            
            try {
                Integer result = usersMapper.insert(users);
                if (0 == result) {
                    result = "fail";
                } else {
                    result = "success";
            } catch (Exception e) {
                log.error(e.getLocalizedMessage(), e.fillInStackTrace());
                result = "fail";
            } finally {
                return result;
            }
        }
    }

    对应的单元测试:

    @RunWith(PowerMockRunner.class)
    @PowerMockRunnerDelegate(SpringRunner.class)
    @PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
    @PrepareForTest({UsersService.class, Date.class, UUID.class})
    @SpringBootTest
    @Transactional
    public class UsersServiceMybatisImplTest {
    
        @Autowired
        private UsersServiceMybatisImpl usersServiceMybatis;
    
        @MockBean
        private EncryptInterface encryptInterface;
    
        @MockBean
        private DateUtils dateUtils;
    
        @Autowired
        private UsersMapper usersMapper;
    
        private UserIn userIn;
        @Before
        public void setUp() throws Exception {
            userIn = new UserIn();
            Mockito.when(encryptInterface.passwordGenerator("hello123")).thenReturn("abcdefghijklmn");
        }
    
        @After
        public void tearDown() throws Exception {
        }
    
    @Test
        public void signUp(){
            Date date = (new GregorianCalendar(2018, 11, 9)).getTime();
            PowerMockito.mockStatic(Date.class);
            PowerMockito.whenNew(Date.class).withNoArgments().thenReturn(date);
            String randomString = "abcdefg";
            UUID uuid = PowerMockito.mock(UUID.class);
            Mockito.when(uuid.toString()).thenReturn(randomString);
            PowerMockito.mockStatic(UUID.class);
            PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
            userIn.setUserId("admin123");
            userIn.setSign("盘古氏");
            userIn.setEmail("pangu@gushen.com");
            userIn.setPassword("hello123");
            userIn.setRePassword("hello123");
            userIn.setIp("127.0.0.1");
            userIn.setNick("盘古");
            userIn.setSchool("混沌大学");
            assertEquals("success", result);
            Users user = usersMapper.selectByPrimaryKey("abcdefg");
            assertEquals(date.toString(), user.getRegTime().toString());
    ......
    } }

    将静态类和静态方法封装成普通 Bean的示例如下:

    工具类:

    @Component
    public class DateUtils {
        public Date generateDate() {
            return new Date();
        }
    }
    @Component
    public class UUIDUtils {
        public Date generateUUID() {
            return UUID.randomUUID();
        }
    }

    Service 类:

    @Service
    public class UsersServiceImpl implements UsersServiceInterface {
    
        @Autowired
        private Users users;
    
        @Autowired
        private UsersMapper usersMapper;
    
        @Autowired
        private DateUtils dateUtils;
    
        @Autowired
        private UUIDUtils uuidUtils;
    
        /**
         * 用户注册 service 方法
         * @param userIn
         * @return
         */
        @Override
        public String signUp(UserIn userIn) {
            String result;
            Date now = dateUtils.generateDate();
            users.setUserId(uuidUtils.generateUUID().toString());
            users.setRegTime(now);
            ......
            
            try {
                Integer result = usersMapper.insert(users);
                if (0 == result) {
                    result = "fail";
                } else {
                    result = "success";
            } catch (Exception e) {
                log.error(e.getLocalizedMessage(), e.fillInStackTrace());
                result = "fail";
            } finally {
                return result;
            }
        }
    }

    单元测试:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @Transactional
    public class UsersServiceMybatisImplTest {
    
        @Autowired
        private UsersServiceMybatisImpl usersServiceMybatis;
    
        @MockBean
        private EncryptInterface encryptInterface;
    
        @MockBean
        private DateUtils dateUtils;
    
        @MockBean
        private UUIDUtils uuidUtils;
    
        @Autowired
        private UsersMapper usersMapper;
    
        private UserIn userIn;
    
        @Before
        public void setUp() throws Exception {
           userIn = new UserIn();
            Mockito.when(encryptInterface.passwordGenerator("hello123")).thenReturn("abcdefghijklmn");
        }
    
        @After
        public void tearDown() throws Exception {
        }
    
        @Test
        public void signUp(){
            Date date = (new GregorianCalendar(2018, 11, 9)).getTime();
            Mockito.when(dateUtils.generateDate()).thenReturn(date);
            UUID uuid = Mockito.mock(UUID.randomUUID());
            Mockito.when(uuid.toString()).thenReturn("abcdefg");
            Mockito.when(uuidUtils.generateUUID()).thenReturn(uuid);
            userIn.setUserId("admin123");
            userIn.setSign("盘古氏");
            userIn.setEmail("pangu@gushen.com");
            userIn.setPassword("hello123");
            userIn.setRePassword("hello123");
            userIn.setIp("127.0.0.1");
            userIn.setNick("盘古");
            userIn.setSchool("混沌大学");
            assertEquals("success", result);
            Users user = usersMapper.selectByPrimaryKey("abcdefg");
            assertEquals(date.toString(), user.getRegTime().toString());
    ...... }
  • 相关阅读:
    设计模式
    工厂方法模式
    简单工厂模式
    tornado自定义Form组件
    tornado
    Tornado框架的知识系列
    Linux基本命令
    day2
    day1
    使用cp复制文件夹却不能打开
  • 原文地址:https://www.cnblogs.com/matchless/p/10442372.html
Copyright © 2011-2022 走看看