51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 3991|回复: 7
打印 上一主题 下一主题

[原创] Mocking with Jmockit

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2009-11-25 14:20:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
JMockit 是用以帮助开发人员编写测试程序的一组工具和API,该项目完全基于 Java 5 SE 的 java.lang.instrument 包开发,内部使用 ASM 库来修改Java的Bytecode。


When writing Unit Tests, it's often necessary to mock classes. There are several good frameworks to do this, such as EasyMock. This works fine in most cases, but it's possible to run into problems when using certain designs.
EasyMock (the same is true for most other mocking frameworks) can only mock public, non static or final methods. In most cases this is not a problem, it will fit most designs. It can be a problem however if you have code that uses, for example, a lot of static methods. It might be an option to refactor this (a lot of static methods might be an indication of bad design), but what if you use classes from external libraries?
JMockit is a small framework that can help out in such cases. It allows you to dynamically replace methods with new definitions. This is based on the Java 1.5 Instrumentation framework. The cool thing about JMockit is that it works with almost every design. It allows you to redefine private, static and final methods. Even no-arg constructors can be redefined.
At the project i'm currently working on we had some trouble figuring out what can and what can't be redefined, and how the method definitions should look like. I've written a small class and a JUnit testcase that redefines all possible methods from the class under test.

在单元测试中,经常需要进行一些mock操作。现在已经有了一些比较不错的框架在做这些事情,比如:EasyMck,他在大多数情况下运行良好,但是对于某些结构的设计却显得无能为力。

EasyMock等众多的mock框架仅能mock一些public,non static or final的方法,在大多数情况下这并没有什么问题,他可以处理大多数的问题,但是当测试的代码包含了一些静态方法,可能就让问题变得难以解决,有一种选择即是重构他(过多的静态方法可能预示着这并不是一个很好的设计),但是当你使用外部引用库所提供的方法,问题又该如何解决呢?

JMockit是一个能帮我们解决以上问题的轻量级框架,他允许你动态的改变已有的方法,这主要基于java 1.5的Instrumentation框架,这样便可以使得JMockit能够适应几乎所有的设计。他允许你重定义private,static and final方法,甚至是no-arg constructors都能够并轻易的重定义。

在实际的项目中有些方法可以重定义而有些不行,为了更好的说明如何对方法进行重定义,下面有一个简单的类和对应测试代码的demo,他尽可能考虑到了几乎所有的情况,供大家方便的学习。(理解不透的地方,希望大家指正)

ClassToMock :
public class ClassToMock {

        private String memberToSet;

        private static String staticMember;

        static {
                staticMember = "Static initialized";
        }

        public ClassToMock() {
                this.memberToSet = "Member set by original constructor";
        }

        public ClassToMock(String value) {
                this.memberToSet = "Member set by original constructor";
        }

        public String publicMethod() {
                return "Original public method";
        }

        protected String protectedMethod() {
                return "Original protected method";
        }

        String defaultMethod() {
                return "Original default method";
        }

        public String methodThatUsesPrivateMethod() {
                return privateMethod();
        }

        private String privateMethod() {
                return "Original private method";
        }

        public String getMemberToSet() {
                return memberToSet;
        }

        public String getStaticMember() {
                return staticMember;
        }
}

ClassToMockTest:
import junit.framework.TestCase;

import mockit.Mockit;

public class ClassToMockTest extends TestCase {

        private ClassToMock mockedClass;

        public static class Replacement {

                static {
                }

                public Replacement() {
                }

                public Replacement(String test) {
                }

                public String publicMethod() {
                        return "Replaced public method";
                }

                public String protectedMethod() {
                        return "Replaced protected method";
                }

                public String defaultMethod() {
                        return "Replaced default method";
                }

                public String privateMethod() {
                        return "Replaced private method";
                }
        }

        protected void setUp() throws Exception {
                Mockit.redefineMethods(ClassToMock.class, Replacement.class);
                mockedClass = new ClassToMock("test");
        }

        protected void tearDown() throws Exception {
                Mockit.restoreAllOriginalDefinitions();
        }

        /**
         * Public methods can be replaced
         */
        public void testReplacePublic() {
                assertEquals("Replaced public method", mockedClass.publicMethod());
        }

        /**
         * Protected methods can be replaced.
         * The replacement method should be declared public however
         */
        public void testReplaceProtected() {
                assertEquals("Replaced protected method", mockedClass.protectedMethod());
        }

        /**
         * Package accessable methods can be replaced
         * The replacement method should be declared public however
         */
        public void testReplaceDefault() {
                assertEquals("Replaced default method", mockedClass.defaultMethod());
        }

        /**
         * Private methods can be replaced
         * The replacement method should be declared public however
         */
        public void testReplacePrivate() {
                assertEquals("Replaced private method", mockedClass
                                .methodThatUsesPrivateMethod());
        }

        /**
         * Non-default constructors can be replaced
         * Your mock definition must have a default constructor however
         */
        public void testReplaceConstructor() {
                assertEquals(null, mockedClass.getMemberToSet());
        }

        /**
         * Default constructors <b>can't</b> be replaced
         */
        public void testReplaceDefaultConstructor() {
                mockedClass = new ClassToMock();
                assertEquals("Member set by original constructor", mockedClass
                                .getMemberToSet());
        }
        /**
         * Static initializers <b>can't</b> be replaced
         */
        public void testReplaceStaticBlock() {
                assertEquals("Static initialized", mockedClass.getStaticMember());
        }
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

  • TA的每日心情
    开心
    2017-9-20 12:50
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]测试小兵

    2#
    发表于 2009-11-25 15:59:19 | 只看该作者
    做白盒测试的吗?哎,偶看不懂
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    3#
     楼主| 发表于 2009-11-25 17:53:42 | 只看该作者

    回复 2# 的帖子

    原帖由 月上百合 于 2009-11-25 15:59 发表
    做白盒测试的吗?哎,偶看不懂


    是的,月上百合,最近在新手区你给我留下了深刻的印象,也看了你整理的一些资料,谢谢啊!!以后多向你学习,可以加你的qq或msn?

    [ 本帖最后由 lijingcheng3359 于 2009-11-25 17:57 编辑 ]
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2015-9-7 11:00
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    4#
    发表于 2009-11-25 18:51:20 | 只看该作者
    貌似是C++,
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    5#
     楼主| 发表于 2009-11-25 19:36:40 | 只看该作者
    原帖由 crystal50112 于 2009-11-25 18:51 发表
    貌似是C++,

    不是c++,是java的。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2015-9-7 11:00
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    6#
    发表于 2009-11-26 11:06:37 | 只看该作者
    哈哈 我孤陋寡闻啦
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    7#
     楼主| 发表于 2009-11-26 11:59:18 | 只看该作者
    原帖由 crystal50112 于 2009-11-26 11:06 发表
    哈哈 我孤陋寡闻啦

    回复 支持 反对

    使用道具 举报

    该用户从未签到

    8#
     楼主| 发表于 2009-11-26 12:02:26 | 只看该作者
    JMockit其实是java单元测试中非常重要的一个框架,因为单元测试中mock是不可避免的,而JMockit恰好可以解决一些其他mock框架无法解决的问题,相信这个对大家还是有帮助的。
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-5-26 13:33 , Processed in 0.076352 second(s), 27 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表