简体   繁体   中英

JMockIt Mocked Method not Mocking

[10/7/06 4:00 Edited example code] I'm trying to test some code (using JMockIt with TestNG) without touching the database, but it appears a mocked method is still actually called. Here's the simplified setup:

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;
    }
}

I wanted to mock the insert operation to prevent an insertion in the actual database, so I tried something like this:

@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");
}

But it appears that the real insert(Object) is still being called. I'm specifying that the class is mocked so all instances should be mocked, right? And I'm specifying that the insert method should be mocked, so why would the real method be getting called?

There's also a second problem with the above. When I define the mock class inside the Expectations block (as above), it seems that only the Row() constructor is being called instead of Row(Object) , and thus the object is not correctly initialized. I fixed this by moving it into a @BeforeTest method and instantiating the class there. Here's what that looks like:

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");
}

So this seems to get the correct constructor to be called, but it still seems that insert() is being called as well. Any insights?

You are not using mocked object to call your fucntion ie private MyObject mock; but a real object test ,

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

Call testStuff() on mock instead of test .

All instances wouldn't be automatically mocked, you have to work with mocked instances.

I was finally able to write my tests such that the right constructor got called and no actual database operation occurred. I think part of the problem I was bumping into was that one of the methods in the Expectations block was getting a different object than I expected for a parameter I wasn't interested in. And I think the other part of my problem was mixing up the roles of a MockUp class and Expectations recordings.

The code under test didn't change. Here's my simplified example again for convenience:

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;
    }
}

Here's essentially what I ultimately ended up with for test code:

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);
}

The key points were that A) I created a MockUp class to override the DB operations, and B) created a local instance of that partially mocked instance to record my Expectations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM