Mock a static method multiple times using JMockit within a JUnit test

pmc255 picture pmc255 · Feb 5, 2011 · Viewed 10.3k times · Source

I have a class with static methods that I'm currently mocking with JMockit. Say it looks something like:

public class Foo {
    public static FooValue getValue(Object something) {
        ...
    }
    public static enum FooValue { X, Y, Z, ...; }
}

I have another class (let's call it MyClass) that calls Foo's static method; I'm trying to write test cases for this class. My JUnit test, using JMockit, looks something like this:

public class MyClassTest extends TestCase {
    @NonStrict private final Foo mock = null;

    @Test public void testMyClass() {
        new Expectations() {
            {
                Foo.getValue((Object) any); result = Foo.FooValue.X;
            }
        };
    }

    myClass.doSomething();
}

This works fine and dandy, and when the test is executed my instance of MyClass will correctly get the enum value of Foo.FooValue.X when it calls Foo.getValue().

Now, I'm trying to iterate over all the values in the enumeration, and repeatedly run the test. If I put the above test code in a for loop and try to set the result of the mocked static method to each enumeration value, that doesn't work. The mocked version of Foo.getValue() always returns Foo.FooValue.X, and never any of the other values as I iterate through the enumeration.

How do I go about mocking the static method multiple times within the single JUnit test? I want to do something like this (but obviously it doesn't work):

public class MyClassTest extends TestCase {
    @NonStrict private final Foo mock = null;

    @Test public void testMyClass() {

        for (final Foo.FooValue val : Foo.FooValue.values() {

            new Expectations() {
                {
                    // Here, I'm attempting to redefine the mocked method during each iteration
                    // of the loop. Apparently, that doesn't work.
                    Foo.getValue((Object) any); result = val;
                }
            };

            myClass.doSomething();
        }

    }
}

Any ideas?

Answer

Rogério picture Rogério · Feb 8, 2011

Instead of "mocking the method multiple times", you should record multiple consecutive return values in a single recording:

public class MyClassTest extends TestCase
{
    @Test
    public void testMyClass(@Mocked Foo anyFoo)
    {
        new Expectations() {{
            Foo.getValue(any);
            result = Foo.FooValue.values();
        }};

        for (Foo.FooValue val : Foo.FooValue.values() {
            myClass.doSomething();
        }
    }
}

It could also be done with a Delegate, if more flexibility was required.