使用JMockIt模拟简单的属性访问

时间:2014-07-16 05:00:06

标签: java unit-testing properties mocking jmockit

我有一个简单的get-set接口:

public interface Foo {

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


此接口是我正在测试的实际类的依赖项。我试图模仿Foo以获得这种有效的行为:

public class MockedFoo implements Foo {

    private String bazField;

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

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


所以我的预期结果是:

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


我能够在withCapture中使用Verification捕获方法参数,但如何设置具有相同输入值的Expectation?看来你可以做其中一个。

有没有办法在JMockIt中表达这一点?我使用的是最新版本(1.9)。


注意:我知道我可以简单地设置一个Mockup<Foo>实例并输入上面的所有代码。但是,我的真实代码要复杂得多,我宁愿不用手工制作整个模拟类。

3 个答案:

答案 0 :(得分:1)

您可以使用Delegate执行此操作。你可以试试这个

要测试的课程

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

测试课

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

}

答案 1 :(得分:1)

注意:这是受到Varun的回答的启发,但我想避免使用反射和中间类。 Rogério也提供了一个可行的替代方案,但它不适合我的测试的整体结构。感谢两者!

<小时/> 以下是我最终的工作方式:

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

答案 2 :(得分:0)

编写这种基于状态的测试的一种方法是:

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

也可以使用JMockit Expectations API(使用Delegate对象)编写等效测试,但由于该API用于基于行为的测试,因此它将更加冗长(即,当你更关心调用哪些方法而不是对象之间的状态转移时。)