Jmokit

2019-05-27  本文已影响0人  紫紫倩

# Junit+Jmokit单元测试

标签(空格分隔):java单元测试

---

>  原理:mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。

- 实质是一种替身的概念,代码基本上完全面向对象 JMockit的API易用,丰富! 写出来的Mock程序代码完全面向对象

#第一阶段 环境准备

1.开发环境已正确配置

idea工具  maven  jdk

2.工程解决JUnit依赖关系(pom.xml)

junit依赖包

jmockit依赖包

Junit Generator架包 用于代码生成器的类

pom.xml 依赖版本

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.9</version>

        </dependency>

        <dependency>

            <groupId>org.jmockit</groupId>

            <artifactId>jmockit</artifactId>

            <version>1.15</version>

        </dependency>

1.打开Settings窗口搜索Junit Generator,如图(两个插件都勾选添加):

![搜索juni插件.jpg-66.5kB][1]

2.JUnitGenerator V2.0插件,可以帮助我们自动生成测试代码。如果搜索junit没有JUnitGenerator V2.0时,如下图操作(下载添加):

 ![下载插件或者导入插件.jpg-137.7kB][2]

 3.JUnitGenerator V2.0插件 配置

 ![日期乱码.jpg-142kB][3]

 4.JUnitGenerator V2.0代码生成操作如下:

  生成路径是当前类路径前面加一个test (test.com.bestpay.algorithm.impl)

![生成测试类的.png-88.2kB][4]

#第二阶段 逻辑

###JMockit有两种测试方式,一种是基于行为的,一种是基于状态的测试。

    Behavior-oriented(Expectations & Verifications :

    通俗点讲,Behavior-oriented是基于行为的mock,对mock目标代码的行为进行模仿,更像黑盒测试

    State-oriented(MockUp<GenericType>) :

    是基于状态的mock,是站在目标测试代码内部的。可以对传入的参数进行检查、匹配,才返回某些结果,类似白盒

    而State-oriented的 new MockUp基本上可以mock任何代码或逻辑,MockUp用于静态方法打桩比较多。

jmockit基本有三个步骤:

(1)打桩。指定要打桩类和函数,模拟返回结果。Expectations()

(2)调用被测方法。被测逻辑执行过程中,之前的打桩数据生效。

(3)判断测试结果是否符合预期。Verifications()

#第三阶段 实操

1.@RunWith(JMockit.class)都被用作运行测试套件 增加运行注解,在这个才可以mocked,一般用于类之上

#####在声明模拟字段和参数时,我们可以使用三种不同的模拟注释

- @Mocked:Mocked修饰的类/接口,是让Jmockit生成一个Mocked对象,这个对象的方法(包含静态方法)返回默认值,如果返回类型是其他引用类型,则返回这个引用类型的Mocked对象.

- @Tested:表示修饰的类,表示测试对象.

- @Injectable:也表示Mocked一个对象,相比Mocked,只不过影响类的一个类的实例.

- Expectations :主要用于录制类/对象的调用,返回值是什么.

- @Mock直接Mock对象方法

- 用Expectation来Mock类于Expectation来Mock实例唯一的不同在于,前者影响类的所有实例,后者只影响某一个类的实例

CountDemo.class

    public class Count extends BaseRedisAggregation {

        public Count() {

            name = "Count";

        }

        @Override

        public Object process(SourceData data) {

            Map fields = paramsParser(data);

                Jedis redis = redisSource.getRedis();

                final String key = fields.get("key").toString();

                final Integer target = 1;

                final String maxStr = redis.hget(key, name);

                if (StringUtils.isNotBlank(maxStr)) {

                    redis.hincrBy(key, name, 1);

                    if (redisSource.expireTime != -1) {

                    redis.expire(key, aggRange * redisSource.expireTime);

                }

            }

            computeAggregation(fields.get("dimsKey").toString(), fields.get("timeKey").toString(),

                    fields.get("singleKey").toString(), aggRange, aggDimention, redis);

            redis.close();

            return null;

        }

        @Override

        public Map<String, Object> paramsParser(SourceData data) {

            String dimsKey = keyPreffix + data.get("dKey");

            String tKey = data.get("tKey");

            String timeKey = "";

            if (StringUtils.isNotBlank(tKey)) {

                timeKey = TimeTransformater.getTimeStr(tKey, aggDimention);

            }

            String singleKey = "Single" + dimsKey;

            String key = singleKey + timeKey;

            String finalTimeKey = timeKey;

            Map<String, Object> algorithmnFileds = new HashMap<String, Object>() {{

                put("dimsKey", dimsKey);

                put("timeKey", finalTimeKey);

                put("key", singleKey + finalTimeKey);

                put("target", data.get("target"));

                put("singleKey", singleKey);

            }};

            return algorithmnFileds;

        }

        public void computeAggregation(String dimKey, String timeStr, String singleKey, int range, char dimensionType, Jedis redis) {

            {

                int totalCount = 0;

                for (int i = 0; i < range; i++) {

                    String timeKey = "";

                    if (dimensionType != '0') {

                        timeKey = TimeTransformater.getLastIntervalTimeStr(dimensionType, timeStr, i);

                    }

                    String currRes = redis.hget(singleKey + timeKey,name);

                    if (StringUtils.isNoneBlank(currRes)) {

                        totalCount += Integer.valueOf(currRes);

                    }

                }

                redis.hset(dimKey, name, String.valueOf(totalCount));

                redis.expire(dimKey, 24 * 60 * 60);

            }

        }

    }

####测试类 CountTestDemo.class

    /**

    * Count Tester.

    * @author <Authors name>

    * @since <pre>01/30, 2019</pre>

    * @version 1.0

    */

    @RunWith(JMockit.class)

    public class CountTest {

        @Tested

        Count count;

        @Mocked

        SourceData sourceDatas;

        @Mocked

        TimeTransformater timeTransformaters;

        @Mocked

        Jedis jedis;

        @Before

    public void before() throws Exception {}

    @After

    public void after() throws Exception {}

    /**

    * Method: process(SourceData data)

    */

    @Test

    public void testComputeAggregation() throws Exception {

        //打桩

        new Expectations(){

            {

          timeTransformaters.getLastIntervalTimeStr(anyChar,anyString,anyInt);      result = 1L;

            }

            {

                jedis.hget(anyString, anyString); result = "100";

            }

            {

                jedis.hset(anyString, anyString, anyString);result = 1l;

            }

            {

                jedis.expire(anyString, anyInt); result =100l;

            }

        };

        count.computeAggregation("1","1","1",1,'a',jedis);

    //判断测试结果

      new Verifications() {

          {

              jedis.hset("1","Count","100");times=1;

          }

      };

    }

    }

> ####常见坑:

>  1.@Tested /@Mocked 时保持格式一致统一对齐

>  2.junit/jmockit依赖架包尽量不要存在多个版本

>  3.测试中方法中,有用到继承属性值,在打桩后直接调用当前类的属性赋予值

1.@Tested /@Mocked 时保持格式一致统一对齐

![格式2.png-48.9kB][5]

3.测试中方法中,有用到继承属性值,在打桩后直接调用当前类的属性赋予值。

![例子.png-46.9kB][6]

  [1]: http://static.zybuluo.com/ziyi/afgogf3c5cu9sd99ft9x0kv4/%E6%90%9C%E7%B4%A2juni%E6%8F%92%E4%BB%B6.jpg

  [2]: http://static.zybuluo.com/ziyi/ag7rxeh0ycgacgh91t297hmj/%E4%B8%8B%E8%BD%BD%E6%8F%92%E4%BB%B6%E6%88%96%E8%80%85%E5%AF%BC%E5%85%A5%E6%8F%92%E4%BB%B6.jpg

  [3]: http://static.zybuluo.com/ziyi/bkzylyo385je9utf9xcsata4/%E6%97%A5%E6%9C%9F%E4%B9%B1%E7%A0%81.jpg

  [4]: http://static.zybuluo.com/ziyi/drtqcs12qmb35jbs4v70g8lb/%E7%94%9F%E6%88%90%E6%B5%8B%E8%AF%95%E7%B1%BB%E7%9A%84.png

  [5]: http://static.zybuluo.com/ziyi/jsc88jokl9dqvqc5glbg90dd/%E6%A0%BC%E5%BC%8F2.png

  [6]: http://static.zybuluo.com/ziyi/5n5vjbscn063g43gk04p56r4/%E4%BE%8B%E5%AD%90.png

上一篇下一篇

猜你喜欢

热点阅读