欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot Service层单元测试

程序员文章站 2022-03-02 15:38:49
...

两个实现类实现同一个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是方法的方法名而不再是类名。