metacubed
metacubed

Reputation: 7271

Mocking simple property access with JMockIt

I have a simple get-set interface:

public interface Foo {

    void setBaz(String baz);
    String getProcessedBaz();    
}


This interface is a dependency of my actual class under test. I'm trying to mock out Foo to have this effective behavior:

public class MockedFoo implements Foo {

    private String bazField;

    @Override
    public void setBaz(String baz) {
        bazField = baz;
    }

    @Override
    public String getProcessedBaz() {
        return "PROCESSED_" + bazField;
    }
}


So my expected result is:

mockedFoo.setBaz("ABC");
assertEquals("PROCESSED_ABC", mockedFoo.getProcessedBaz());


I was able to capture the method argument using withCapture in a Verification, but how do I set up an Expectation with that same input value? It seems you can do either one or the other.

Is there a way to express this in JMockIt? I'm using the latest version (1.9).


NOTE: I'm aware that I can simply set up a Mockup<Foo> instance and put in all the code above. However, my real code is much more complex and I would prefer not to hand-craft the entire mock class.

Upvotes: 2

Views: 2776

Answers (3)

metacubed
metacubed

Reputation: 7271

NOTE: This was inspired by Varun's answer, but I wanted to avoid using reflection and intermediate classes. Rogério also provided a viable alternative, but it did not fit into the overall structure of my test. Thanks to both!


Here's how I finally got it working:

public interface Foo {
    void setBaz(String baz);
    String getProcessedBaz();
}

@RunWith(JMockit.class)
public class FooTest {
    @Injectable
    private Foo mockedFoo = null;

    @Test
    public void testBaz() { 
        new Expectations() {
            private String bazState; // Variable inside Expectations stores the state between calls

            {
                mockedFoo.setBaz(anyString);
                result = new Delegate() {
                    void setBaz(String baz) { bazState = baz; }
                };

                mockedFoo.getProcessedBaz();
                result = new Delegate() {
                    String getProcessedBaz() { return "PROCESSED_" + bazState; }
                };
            }
        };

        mockedFoo.setBaz("ABC");
        assertEquals("PROCESSED_ABC", mockedFoo.getProcessedBaz());
    }
}

Upvotes: 1

वरुण
वरुण

Reputation: 1665

You can do this using Delegate. You may try this

Class to test

public interface Foo {

    void setBaz(String baz);
    String getProcessedBaz();    
}

class FooSubClass implements Foo {

    private String bazField;

    @Override
    public void setBaz(String baz) {
        bazField = null;
    }

    @Override
    public String getProcessedBaz() {
        return bazField;
    }
}

Test class

import mockit.Capturing;
import mockit.Deencapsulation;
import mockit.Delegate;
import mockit.NonStrictExpectations;

import org.junit.Before;
import org.junit.Test;


public class FooTest 
{
    FooSubClass fooSubClass;
    @Capturing Foo fooMocked;
    @Before
    public void setUp()
    {
        fooSubClass = new FooSubClass();
    }
    @Test
    public void testAMethod()
    {
        new NonStrictExpectations()
        {
            {
                fooMocked.setBaz(anyString);
                result = new Delegate()
                        {
                    void setBaz(String baz)
                    {
                        Deencapsulation.setField(fooSubClass, "bazField", baz);
                    }
                };
                times = 1;

                fooMocked.getProcessedBaz();
                result = new Delegate()
                {
                    String getProcessedBaz()
                    {
                        return "PROCESSED_" + Deencapsulation.getField(fooSubClass, "bazField");
                    }
                };
                times = 1;
            }
        };
        fooSubClass.setBaz("abc");
        System.out.println(fooSubClass.getProcessedBaz());
    }

}

Upvotes: 1

Rog&#233;rio
Rog&#233;rio

Reputation: 16380

One way to write such an state-based test is:

public interface Foo {
    void setBaz(String baz);
    String getProcessedBaz();
    void someOtherMethod();
}

public static class ClassUnderTest {
    String doSomething(Foo foo) {
        foo.setBaz("ABC");
        foo.someOtherMethod();
        return foo.getProcessedBaz();
    }
}

@Test
public void mockFoo() {
    Foo foo = new MockUp<Foo>() {
        String baz;
        @Mock void setBaz(String baz) { this.baz = baz; }
        @Mock String getProcessedBaz() { return "PROCESSED_" + baz; }
    }.getMockInstance();

    String res = new ClassUnderTest().doSomething(foo);

    assertEquals("PROCESSED_ABC", res);
}

An equivalent test can also be written with the JMockit Expectations API (using Delegate objects), but it would be more verbose as that API is meant for behavior-based testing (ie, when you care more about which methods get invoked than state-transfer between objects).

Upvotes: 0

Related Questions