微服务怎么单元测试 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MakHoCheung
V2EX    问与答

微服务怎么单元测试

  •  
      MakHoCheung 2022-01-25 09:35:48 +08:00 3628 次点击
    这是一个创建于 1435 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:公司项目是用 Nacos 做服务发现与注册以及配置中心的,而且是公共的,开发微服务都是本地区连这个公共 Nacos 。

    疑问:编写单元测试一个服务的时候可以 mock 其他需要用到的服务,但是每次跑单元测试的时候都要去连 Nacos 非常的慢,不知大厂的最佳实践是什么样的?

    15 条回复    2022-01-25 17:22:42 +08:00
    chihiro2014
        1
    chihiro2014  
       2022-01-25 09:43:55 +08:00
    Spring Contract ?
    x66
        2
    x66  
       2022-01-25 09:44:03 +08:00
    单元测试本来就不应该依赖其他服务,所有外部依赖都应该被 mock 。。
    MakHoCheung
        3
    MakHoCheung  
    OP
       2022-01-25 09:57:21 +08:00
    @x66 但是像 Spring 这种依赖注入的框架,要测某个 Service 的方法就要启动整个 Spring 应用,这时候它要去连 Nacos ,是不是不应该把整个 Spring 应用跑起来?
    MakHoCheung
        4
    MakHoCheung  
    OP
       2022-01-25 09:58:11 +08:00
    @chihiro2014 谢谢,去深究一下
    Alchemistboy
        5
    Alchemistboy  
       2022-01-25 10:22:30 +08:00
    如果你们测试的时候不需要使用内存数据库的话,使用构造器的注入方法写业务类,测试的时候就不用启动 spring 容器,直接测试业务代码。
    类似这样:
    ``
    public class ATest {

    private final A a;
    private final B b;
    private final C c;
    private final D d;

    {
    b = Mockito.mock(B.class);
    c = Mockito.mock(C.class);
    d = Mockito.mock(D.class);
    a = new A(b, c, d);
    }

    @Test
    public void test1() {

    // 参数准备 param1 param2 param3
    when(a.excute(any())).thenReturn(param1);
    when(b.excute(any(),any())).thenReturn(param2);
    when(c.excute(any(),any(),any())).thenReturn(param3);

    String message = "";
    String respOnse= a.excuteService(message);
    Assert.notNull(response);
    }
    }
    ``
    Alchemistboy
        6
    Alchemistboy  
       2022-01-25 10:22:49 +08:00 div class="sep5">
    如果你们测试的时候不需要使用内存数据库的话,使用构造器的注入方法写业务类,测试的时候就不用启动 spring 容器,直接测试业务代码。
    chihiro2014
        7
    chihiro2014  
       2022-01-25 10:37:48 +08:00
    @MakHoCheung 这个是龙之春推荐的一种微服务测试方式
    leafre
        8
    leafre  
       2022-01-25 10:51:31 +08:00
    先把单元和集成测试分不清

    单测不负责检查跨类或者跨系统的交互逻辑,那是集成测试的领域。
    RichardYyf
        9
    RichardYyf  
       2022-01-25 11:31:05 +08:00
    外部依赖都应该被 mock ,如果是调用外部服务或者 API ,应该设置防腐层,对防腐层的方法做 mock 。对于外部 mq/cache 之类的中间件,为了保证单测的准确性,可以用 testContainer 这类容器技术来 mock 。总之一个单元测试不应该依赖外部环境。
    MakHoCheung
        10
    MakHoCheung  
    OP
       2022-01-25 11:37:55 +08:00
    @leafre 比如测试 DiscountService#calculateDiscount 这个计算折扣的方法,假如折扣规则需要调用其他服务,这些其他服务我可以 mock ,这个算单元测试还是集成测试?
    其次我主要问的是 DiscountService 里面有其他 Spring 组件的,所以要测 DiscountService 的话要启动整个 Spring Boot 应用,启动 Spring Boot 应用要连 Nacos 很慢,耗时比测试多很多,有没有最佳实践。
    5 楼的做法应该是最佳实践,不启动 Spring Boot ,只是要手动进行依赖管理
    MakHoCheung
        11
    MakHoCheung  
    OP
       2022-01-25 11:40:25 +08:00
    “testContainer 这类容器技术来”,最近刚好想保证 redis 数据正确,有什么好的容器技术么
    winglight2016
        12
    winglight2016  
       2022-01-25 14:56:32 +08:00
    本地启动 naocs 服务还是很慢吗?
    leafre
        13
    leafre  
       2022-01-25 14:58:05 +08:00
    @MakHoCheung 我的理解 mock 后切断了外部依赖是属于单元测试,但是 mock 写起来麻烦,费时收益小,所以很少写 UT 。我们有专门搭建的开发环境容器群,包括发现服务、各种中间件,覆盖接口集成测试即可。连接慢叫老板加钱
    leon0318
        14
    leon0318  
       2022-01-25 15:02:35 +08:00 via iPhone
    @MakHoCheung 是的
    sampeng
        15
    sampeng  
       2022-01-25 17:22:42 +08:00
    最理想的情况下:是的,所有外部都 mock 。
    次理想情况下:把外部调用隔离开。就拿你说的计算折扣的方法。你不应该依赖外部的输入,而是你自己造数据传递给待测方法,观察输入和输出是不是符合期望
    现实:谁愿意写谁写,996 时间不够
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5365 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 06:41 PVG 14:41 LAX 22:41 JFK 01:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86