5

I am trying to unit test a class where one of its methods returns an instance of a collaborator class: depending on the values of its arguments it either returns a newly created instance, or a saved, previously created instance.

I mock the constructor call in an Expectations and set the result to a value that is a mocked instance of the collaborator. But when I test the method with parameter values that cause it to create a new instance, the mocked constructor, and therefore the method, does not return the expected value.

I have simplified this down to the following:

package com.mfluent;
import junit.framework.TestCase;
import mockit.Expectations;
import mockit.Mocked;
import mockit.Tested;
import org.junit.Assert;
import org.junit.Test;

public class ConstructorTest extends TestCase {

    static class Collaborator {
    }

    static class ClassUnderTest {
        Collaborator getCollaborator() {
            return new Collaborator();
        }
    }

    @Tested
    ClassUnderTest classUnderTest;

    @Mocked
    Collaborator collaborator;

    @Test
    public void test() {
        new Expectations() {
            {
                new Collaborator();
                result = ConstructorTest.this.collaborator;
            }
        };

        Collaborator collaborator = this.classUnderTest.getCollaborator();
        Assert.assertTrue("incorrect collaborator returned", collaborator == this.collaborator);
    }
}

Any ideas on why this test fails and how to make it work would br greatly appreciated.

Thanks in advance,

Jim Renkel Senior Technical Staff mFluent, Inc. LLC

Jim Renkel
  • 53
  • 1
  • 4

1 Answers1

3

Change the @Mocked annotation to @Capturing, like this:

@Capturing
Collaborator collaborator;

This allows the test to pass for me.

This is a little bit of voodoo magic, in my opinion, but if you'd like to read more, take a look at Capturing internal instances of mocked types in the JMockit tutorial.

Also see Using JMockit to return actual instance from mocked constructor

Community
  • 1
  • 1
Jeff Olson
  • 6,323
  • 2
  • 22
  • 26
  • Thank you so much for your help! When I applied your fix to my real test case, it still didn't work. But after some more digging and experimentation, I was able to get it to work. The problem was that I had to capture multiple constructions, so I had to have multiple capturing fields, each with a maxInstances = 1 attribute. Non-obvious, but as I said, it works. Again, thank you very much for your help. Jim Renkel Senior Technical Staff mFluent, Inc. LLC – Jim Renkel May 16 '13 at 20:42
  • Great, glad it worked for you. And welcome to StackOverflow! – Jeff Olson May 17 '13 at 00:36
  • Instead, try simply using `@Mocked Collaborator mock`. It will mock *all* instances of the class, present and future. Usually, you should simply specify the behavior expected from `Collaborator` objects; there is no need to worry about the instances, unless you need different behavior from different instances of the same mocked class. – Rogério May 17 '13 at 11:53