【问题标题】:JMockIt Mocked Method not MockingJMockIt 模拟方法不模拟
【发布时间】:2016-10-11 04:10:46
【问题描述】:

[10/7/06 4:00 编辑的示例代码] 我正在尝试在不接触数据库的情况下测试一些代码(使用 JMockIt 和 TestNG),但实际上仍然调用了一个模拟方法。这是简化的设置:

class DBRow {
    public DBRow() { }
    public DBRow(Object obj) {
        initialize(obj);
    }
    public void insert() {
        actuallyAddRowToDatabase();
    }
}

class MyObject extends DBRow {
    MyObject(Object obj) {
        super(obj);
    }
    public void insert(Object obj) {
        doSomething(obj);
        insert();
    }
}

class Factory {
    static MyObject createObject(Object obj1, Object obj2) {
        MyObject newObj = new MyObject(obj1);
        newObj.insert(obj2);
        return newObj;
    }
}

我想模拟插入操作以防止在实际数据库中插入,所以我尝试了这样的操作:

@Test
public void testCreation() {
    new Expectations(MyObject.class) {
        MyObject mock = new MyObject(null) {
            @Mock
            public void insert(Object obj) { }
        };
    {
        new MyObject(anyString);   result = mock;
    }};

    MyObject test = Factory.createObject("something", "something else");
}

但看起来真正的insert(Object) 仍在被调用。我指定类是模拟的,所以所有的实例都应该被模拟,对吧?而且我指定应该模拟插入方法,那么为什么要调用真正的方法呢?

上面还有第二个问题。当我在 Expectations 块中定义模拟类时(如上),似乎只调用了 Row() 构造函数而不是 Row(Object),因此对象未正确初始化。我通过将其移入@BeforeTest 方法并在那里实例化该类来解决此问题。看起来是这样的:

private MyObject mock;

@BeforeTest
public void beforeTest() {
    new MockUp<MyObject>() {
        @Mock
        public void insert(Object obj) { }
    };
    mock = new MyObject("something");
}

@Test
public void testCreation() {
    new Expectations(MyObject.class) {{
        new MyObject(anyString);   result = mock;
    }};

    MyObject test = Factory.createObject("something", "something else");
}

所以这似乎调用了正确的构造函数,但似乎仍然调用了insert()。有什么见解吗?

【问题讨论】:

    标签: java unit-testing testng jmockit database-testing


    【解决方案1】:

    你没有使用模拟对象来调用你的函数,即private MyObject mock;,而是一个真实的对象test

    MyObject test = new MyObject("something", "something else");
    

    请在mock而不是test上致电testStuff()

    不会自动模拟所有实例,您必须使用模拟实例。

    【讨论】:

    • testStuff() 没有问题。事实上,我将从我的示例中删除它。问题是构造期间的 insert() 。我将编辑我的示例以希望对其进行澄清。但是,您说“不会自动模拟所有实例”,但在文档中它说:“如果 [在期望构造函数中] 给出了 Class 对象......指定类的所有实例都将被视为模拟实例”。你能澄清你的说法吗?
    • 指向我引用的文档。了解Expectations 是在模拟实例上调用的记录阶段。它不是模拟对象创建阶段。使用 new MockUpMock 和 Ìnjectable` 创建的模拟对象
    • 另外,阅读您的代码非常令人困惑。你MyObjectdefinition 只有一个构造函数,MyObject(Object obj),但在你的测试代码中,你有,new MyObject("something", "something else"); 所以我不确定我在看什么。如果您的真实方法被调用,那么您是在真实对象上调用方法而不是假对象。
    • Sabir,感谢您抽出宝贵时间回复。我对代码感到抱歉。当我编辑它时,我没有更新那些构造函数。我相信它现在是自洽的。至于引用,我在这里找到它:link 就在代码示例下方。
    • 我可能在这里找到了答案:link。明天我会试一试(使用@Capturing)并报告。
    【解决方案2】:

    我终于能够编写测试,以便调用正确的构造函数并且没有发生实际的数据库操作。我认为我遇到的部分问题是 Expectations 块中的一种方法得到的对象与我对我不感兴趣的参数的预期不同。而且我认为我的问题的另一部分是混淆了MockUp 类和期望记录的角色。

    被测代码没有改变。为方便起见,再次简化示例:

    class DBRow {
        public DBRow() { }
        public DBRow(Object obj) {
            initialize(obj);
        }
        public void insert() {
            actuallyAddRowToDatabase();
        }
    }
    
    class MyObject extends DBRow {
        MyObject(Object obj) {
            super(obj);
        }
        public void insert(Object obj) {
            doSomething(obj);
            insert();
        }
    }
    
    class Factory {
        static MyObject createObject(Object obj1, Object obj2) {
            MyObject newObj = new MyObject(obj1);
            newObj.insert(obj2);
            return newObj;
        }
    }
    

    这基本上是我最终得到的测试代码:

    Object something;
    Object somethingElse;
    
    @BeforeTest
    public void beforeTest() {
        new MockUp<MyObject>() {
            @Mock
            public void insert() { }  // override the "actual" DB insert
        };                            // of Row.insert()
    }
    
    @Test
    public void testCreation() {
        MyObject mock = new MyObject(something);  // object correctly init'd
                                                  // by Row.initialize(Object)
        new Expectations(MyObject.class) {{
            new MyObject(something);     result = mock;
            mock.insert(somethingElse);
        }};
    
        MyObject test = Factory.createObject(something, somethingElse);
    }
    

    关键点是 A) 我创建了一个 MockUp 类来覆盖数据库操作,并且 B) 创建了该部分模拟实例的本地实例来记录我的期望。

    【讨论】:

      猜你喜欢
      • 2014-12-17
      • 2013-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 2021-01-07
      • 2014-12-12
      相关资源
      最近更新 更多