springboot Service层单元测试

两个实现类实现同一个Service接口

public interface CustomUrlService {
    List<ShopMetrics> getShopMetrics();
}

@Service
public class CustomUrlServiceImpl implements CustomUrlService {
    @Override
    public List<ShopMetrics> getShopMetrics() {
        return null;
    }
}


@Service
public class CustomUrlServiceImpl2 implements CustomUrlService {
    @Override
    public List<ShopMetrics> getShopMetrics() {
        return Arrays.asList(new ShopMetrics(34L, 34L));
    }
}

使用的时候如果使用接口作为类型,直接使用@Autowired是无法找到具体是哪个bean的,因为@Autowired默认是按照类型注入的,需要加上@Qualifier注解指定实现类的bean id,如果@Service中没有指定bean id(bean name),默认是类名的首字母小写作为bean name。当然也可以使用@Resource注解,它默认是by name 注入的,所以变量名需要和待注入的实现类的bean name保持一致,如下所示:

    @Autowired
    @Qualifier("customUrlServiceImpl")
    private CustomUrlService customUrlServiceImpl;

    @Resource
    private CustomUrlService customUrlServiceImpl2;

@TestConfiguration

我之前在springboot中写单元测试喜欢全部按照下面这种来写测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomUrlServiceImplTest {}

但是@SpringBootTest是把整个spring容器启动起来,然后把测试环境给你准备好,这样也是可以的,但是有时候只是显得有点有点笨重,看日志就知道整个应用不管和这个单元测试有关没关的都被启动了,而我们只是为了跑一个单元单元测试。
看了参考资料1之后,我才知道了单元测试不一定需要启动整个应用,层与层之间也可以并且应该隔离测试。如果上层测试需要用到下层的依赖,就使用mock的方式构造一个依赖。比如测试DAO层可以使用@DataJpaTest注解;测试controller层可以使用@WebMvcTest;测试Service层可以使用@TestConfiguration把需要用到Bean依赖进来。下面是测试Service层的一个例子:

@RunWith(SpringRunner.class)
public class CustomUrlServiceImplTest {
    @TestConfiguration
    static class prepareCustomServices{
        @Bean
        public CustomUrlService getCustomUrlServiceImpl() {
            return new CustomUrlServiceImpl();
        }

        @Bean
        public CustomUrlService getCustomUrlServiceImpl2() {
            return new CustomUrlServiceImpl2();
        }
    }

    @Autowired
    @Qualifier("getCustomUrlServiceImpl")
    private CustomUrlService customUrlServiceImpl;
    
    @Resource
    private CustomUrlService getCustomUrlServiceImpl2;
    
    @Test
    public void getShopMetrics() {
        assertNull(customUrlServiceImpl.getShopMetrics());
        assertNotNull(getCustomUrlServiceImpl2.getShopMetrics());
    }
}

现在再运行@Test标注的单元测试就不会启动整个springboot容器中了。这里面需要注意的是使用 @Bean放入到spring容器的的bean的默认id是方法的方法名而不再是类名。

参考资料

  1. https://www.baeldung.com/spring-boot-testing
  2. https://dzone.com/articles/unit-and-integration-tests-in-spring-boot-2
posted @ 2019-10-18 16:25  木白的菜园  阅读(20279)  评论(0编辑  收藏  举报