• Mock&Spring集成


    Mock&Spring集成#

    常规Mock单元测试##

    请参考上一篇文档Mock

    mock框架的功能性对比##

    http://jmockit.github.io/MockingToolkitComparisonMatrix.html

    从模拟支持特性上做了详细的对比,比如是否支持模拟static、构造函数等等。

    集成测试##

    大部分Web应用项目基于Spring平台构建,集成测试主要关注点是Junit+Spring+Mock集成!
    从Spring项目2.x开始就有基于Junit的测试辅助包(Spring-test)!
    重点关注引入Mock框架后Spring与其集成!

    温馨提示Jmockit作为本文代码示例的模拟框架,其它模拟选型框架的测试结果直接作为结论。

    关注点##

    Mock测试框架是否能够和Spring完美集成?

    • 版本&升级(mock框架版本和Spring版本是否完全兼容,无包冲突,是否可升级,比如Spring从2.x->3.x->4.x)
    • 内容&特性(mock框架提供的各种模拟策略特性能否和Spring-test提供的各种测试支持类兼容)

    基于Spring的测试点##

    虚拟机运行环境版本: 1.7.0_60

    1)基础包版本:

    • Spring:2.5.6/3.x.x/4.x.x, Junit:4.x

    2)Mock选型:

    • Mockito:1.9.5, PowerMock-mockito-*: 1.5.5
    • Jmock:2.6.0
    • Jmockit:1.14

    3)模拟测试用例

    • 模拟Spring单例bean方法
    • 模拟静态方法调用

    备注:实际测试是分开多个测试Demo,spring+mockito

    示例代码##

    UserService,StaticUserService,UserAction类请参考上一篇文档Mock

    静态公共方法模拟###

    package jmockit;
    
    import mockit.NonStrictExpectations;
    import mockit.Verifications;
    
    import org.junit.Test;
    import org.wit.service.StaticUserService;
    import org.wit.service.UserAction;
    
    public class MockForPublicStaticDemo {
    
        @Test
        public void demo() {
            new NonStrictExpectations(StaticUserService.class) {
                {
                    StaticUserService.sayHello(anyString);
                    result = "mock";
                }
            };
    
            // assertEquals("mock", StaticUserService.sayHello("real"));
            UserAction userAction = new UserAction();
            userAction.executeForPublicStatic1("real");
    
            new Verifications() {
                {
                    StaticUserService.sayHello(anyString);
                    times = 1;
                }
            };
        }
    }
    
    

    Spring Singleton Bean方法模拟###

    package jmockit;
    
    import mockit.NonStrictExpectations;
    import mockit.Verifications;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.wit.service.StaticUserService;
    import org.wit.service.UserAction;
    import org.wit.service.UserService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class MockForSpringJunitDemo {
    
        @Autowired
        private UserAction userAction;
        
        @Autowired
        private UserService userService;
    
        @Test
        public void demo() throws Exception {
            new NonStrictExpectations(StaticUserService.class) {
                {
                    StaticUserService.sayHello(anyString);
                    result = "mock";
                }
            };
    
            userAction.executeForPublicStatic1("real");
    
            new Verifications() {
                {
                    StaticUserService.sayHello(anyString);
                    times = 1;
                }
            };
            
        }
        
        /**
         * 
         * <pre>
         * 模拟bean的方法.
         * UserService sayHello模拟调用, sayHi为真实调用.
         * </pre>
         *
         * @throws Exception
         */
        @Test
        public void beanDemo() throws Exception{
            new NonStrictExpectations(userService) {
                {
                    userService.sayHello(anyString);
                    result = "mock";
                }
            };
    
            userAction.executeForPublic("hi");
    
            new Verifications() {
                {
                    userService.sayHello(anyString);
                    times = 1;
                }
            };
            
        }
    }
    
    

    静态私有方法模拟###

    package jmockit;
    
    import static mockit.Deencapsulation.invoke;
    import mockit.Expectations;
    import mockit.Verifications;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.wit.service.StaticUserService;
    import org.wit.service.UserAction;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class MockForSpringJunitPrivateStaticDemo {
    
        @Autowired
        private UserAction userAction;
    
        @Test
        public void demo() throws Exception {
    
            new Expectations(StaticUserService.class) {
                {
                    invoke(StaticUserService.class, "secreteSayHi", anyString);
                    invoke(StaticUserService.class, "secreteSayHello", anyString);
                    result = "mock";
                }
    
            };
    
            userAction.executeForPrivateStatic("real");
    
            new Verifications() {
                {
                    invoke(StaticUserService.class, "secreteSayHi", anyString);
                    times = 1;
                    invoke(StaticUserService.class, "secreteSayHello", anyString);
                    times = 1;
                }
            };
        }
    
    }
    
    

    结论##

    方案:Mockito:1.9.5, PowerMock-mockito-*: 1.5.5

    • Spring-test 3.x以上版本启用了新测试基类,并提供新的测试运行器(SpringJunit4ClassRunner.class), 它会和PowerMock提供的测试运行器(PowerMockRunner.class)产生冲突,如果选择PowerMockRunner会导致找不到Spring配置文件的错误发生;
    • Spring-test 2.5.6的测试基类AbstractDependencyInjectionSpringContextTests和PowerMock兼容,但此类在Spring3.x之后的版本中过时。
    • 采用官方提供的PowerMockRule会产生虚拟机崩溃的错误详细日志见下文
    2015-11-27 15:58:48,015 INFO  context.TestContextManager - Could not instantiate TestExecutionListener class [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.
    2015-11-27 15:58:48,019 INFO  context.TestContextManager - Could not instantiate TestExecutionListener class [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.
    2015-11-27 15:58:48,112 INFO  xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
    2015-11-27 15:58:48,191 INFO  support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@361fc5a2: startup date [Fri Nov 27 15:58:48 GMT+08:00 2015]; root of context hierarchy
    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000000291e2ba, pid=15700, tid=14928
    #
    # JRE version: Java(TM) SE Runtime Environment (7.0_60-b13) (build 1.7.0_60-ea-b13)
    # Java VM: Java HotSpot(TM) 64-Bit Server VM (24.60-b09 mixed mode windows-amd64 compressed oops)
    # Problematic frame:
    # j  java.lang.reflect.ReflectAccess.copyField(Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field;+1
    #
    # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
    #
    # An error report file with more information is saved as:
    # D:workspaceworkspace-demosmockitohs_err_pid15700.log
    Compiled method (c2)     861   16             java.lang.Object::<init> (1 bytes)
     total in heap  [0x0000000002969310,0x0000000002969540] = 560
     relocation     [0x0000000002969430,0x0000000002969440] = 16
     main code      [0x0000000002969440,0x00000000029694c0] = 128
     stub code      [0x00000000029694c0,0x00000000029694d8] = 24
     oops           [0x00000000029694d8,0x00000000029694e0] = 8
     scopes data    [0x00000000029694e0,0x00000000029694f0] = 16
     scopes pcs     [0x00000000029694f0,0x0000000002969520] = 48
     dependencies   [0x0000000002969520,0x0000000002969528] = 8
     handler table  [0x0000000002969528,0x0000000002969540] = 24
    #
    # If you would like to submit a bug report, please visit:
    #   http://bugreport.sun.com/bugreport/crash.jsp
    #
    
    

    方案: Jmock:2.6.0,Jmockit:1.14

    • Jmock&Jmockit在测试运行器上选择Spring的测试运行器,和Spring各个版本兼容良好。
    • 模拟Spring 单例Bean的方法和静态方法都能正常模拟,请关注静态私有方法和公共方法的差异

    QA##

  • 相关阅读:
    k8s中job和cronjob相关的yaml文件
    k8s中controller-manager相关的yaml文件
    常用的Linux命令
    单一职责
    func和Expression
    策略模式和简单工厂
    练习7第三题
    练习7第二题
    练习7第一题
    实验6 数组1-1
  • 原文地址:https://www.cnblogs.com/fangfan/p/5001149.html
Copyright © 2020-2023  润新知