草庐IT

Mock单元测试----对Controller层进行单独测试,不调用Service层

樾云枫 2023-07-24 原文

前言:根据相关需求,需要对编写的代码进行逻辑检测以及功能的完整性,从而开始了单元测试之路。在编写的中间段时,突然被 不经过Service层直接测试Controller层 这个要求难住了。在我看来,单元测试除了Junit还是Junit,属实是学艺不精,之后接触了Mock,才发现Mock太牛逼了,爱死了。

回归正题,单独使用Juit测试,我目前是不太会的,而且需要保证使用Controller层时不调用Service,还要对Controller的返回值进行验证,对于刚开始接触Mock单元测试的人来说肯定是个难点。

例如:我们要对Controller类中的select方法类进行一个测试,保证其能够顺利执行Service的selectComment方法,但是要求不能调用此方法,怎么做呢?

@Override
    public RestResponse<CareCourseComment> select(CareCourseComment careCourseComment){
        return targetService.selectComment(careCourseComment);
    }

这里不再赘述mock的配置和依赖,请自行装配!

在测试类中,我们首先需要进行Controller层和Service层的自动装配

    @Autowired
    private CareCourseCommentService targetService;
    @Autowired
    private CareCourseCommentController targetController;

然后实现代码如图所示,接下来慢慢解释

    @Test
    public void testSelectControllerTest() throws Exception{
        RestResponse<IPage<CareCourseComment>> list = new RestResponse<>();
        //数据定义
        CareCourseComment careCourseComment = new CareCourseComment();
        careCourseComment.setOpenid("533412d");
        Map careCourseCommentMaps = JSON.parseObject(JSON.toJSONStringWithDateFormat(careCourseComment,"yyyy-MM-dd HH:mm:ss"),Map.class);
        //mock模拟Service
        CareCourseCommentService careCourseCommentService = mock(CareCourseCommentService.class);
        //设置范围
        ReflectionTestUtils.setField(targetController,"targetService",careCourseCommentService );
        when(careCourseCommentService.selectComment(any())).thenReturn(list);
        //进行实际输入验证
        RestResponse<IPage<CareCourseComment>> careList = targetController.select(careCourseCommentMaps);
        //重置模拟,进行还原
        ReflectionTestUtils.setField(targetController,"targetService",targetService);
        //断言,结果比对
        assertEquals(list,careList);
    }

这里的RestResponse是应答响应,和ApiResponse一样,有code、message和data。因为addComment是返回RestResponse,所以这里的Controller类接收到的也是RestResponse。后面的两行是进行数据的模拟,Service类是接收的Map类型的,所以需要进行类型转换(这里的JSON.toJSONStringWithDateFormat中的"yyyy-MM-dd HH:mm:ss"主要是对入参时的时间进行格式转换,防止传入的时间变成时间戳格式,然后可能之后再用SimpleDateFormat转换时变成CST格式,真的是太心累了)。

之后我们需要首先对Service进行mock的模拟,根据要求我们不能真的调用Service,直接使用mock来进行模拟,令它返回一个我们想要的值。接下来就是重点了!我们需要先对测试进行一个范围限制,将他限制在Controller层的targetService里,当我们使用Controller层的targetService时,它调用的是我们模拟的Service,而不是@Autowired自动装配的原有的Service。

when().thenReturn()方法用于确认当我执行到Service的selectComment时,不管我传入的是什么值,都会返回我定义的list,之后便是进行实际的输入验证,将前面定义的数据传到Controller层的select方法中进行实际的验证,然后进行结果比对。

这里需要注意:在验证完后需要对Controller的targetService进行还原!!!否则会导致其他的测试类也会被这个mock模拟的Service所替换。可能导致当整一个测试类进行运行时,会使得其他的测试类与预期结果出现大偏差甚至报错,在debug的过程下,可以清楚地看到Controller层的targetSerice是由mock模拟的。

有关Mock单元测试----对Controller层进行单独测试,不调用Service层的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  5. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  6. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  7. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  8. ruby-on-rails - rails : How to make a form post to another controller action - 2

    我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

  9. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  10. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

随机推荐