Question

I want to mock the following class using JMockit:

public class A {

    private int n;

    public A(int n) {
        this.n = n;
    }

    public boolean isCorrect() {
        return n % 2 == 0;
    }
}

The class is initialized throughout my code, and I usually don't have access to that part of the code in my test.
At some of my tests I want to mock it so that if the class is initialized with the value of 3, 'isCorrect' will return true (which is not the normal behavior), and at some other tests I want to mock it so that 'isCorrect' will return false no matter how it was initialized.

I tried to find a way to do it in the documentation, but it wasn't so user-friendly and I gave up on it.

Was it helpful?

Solution 2

Thanks @assylias for you answer. I think I found a better way to implement the first mock, which combines the ideas from your first and second (after edit) answers. It goes like this:

new MockUp<A> () {

    private int n;

    @Mock
    public void $init(Invocation inv, int n) {
        this.n = n;
        inv.proceed();
    }

    @Mock
    public boolean isCorrect(Invocation inv) {
        if (n == 3) {
            return true;
        }
        return inv.proceed();
    }
};

Update

For the second mock (the brute false return), this will do:

new MockUp<A> () {

    @Mock
    public boolean isCorrect() {
        return false;
    }
};

And again, thanks to @assylias for helping me with this :)

OTHER TIPS

For your first case, you can do:

new MockUp<A> () {
     private int n;
     @Mock public void $init(int n) { this.n = n; }
     @Mock public boolean isCorrect() { return n == 3; }
};

And for your second example:

new MockUp<A> () {
     @Mock public boolean isCorrect() { return false; }
};

For example, this prints false, true, false, false:

new MockUp<A> () {
     private int n;
     @Mock public void $init(int n) { this.n = n; }
     @Mock public boolean isCorrect() { return n == 3; }
};
System.out.println(new A(2).isCorrect());
System.out.println(new A(3).isCorrect());

new MockUp<A> () {
     @Mock public boolean isCorrect() { return false; }
};
System.out.println(new A(2).isCorrect());
System.out.println(new A(3).isCorrect());

EDIT

Following your comment, one way to mock the class only for certain values of n is to use reflection to check the value of the field:

new MockUp<A> () {
     @Mock public boolean isCorrect(Invocation invocation) {
        // Gets the invoked instance.
        A a = invocation.getInvokedInstance();
        int n = Deencapsulation.getField(a, "n");
        if (n == 3) return true;
        else return a.isCorrect();
     }
};

But it becomes a bit fragile because it depends on the name of the variable in your class A.

A maybe better alternative would be to give a package-protected getter for testing purposes in your class A: int getN() { return n; } and you don't need reflection any more.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top