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

Java 使用JMockIt模拟简单属性访问,java,unit-testing,properties,mocking,jmockit,Java,Unit Testing,Properties,Mocking,Jmockit,我有一个简单的获取集界面: public interface Foo { void setBaz(String baz); String getProcessedBaz(); } 这个接口是我的实际测试类的依赖项。我试图模仿Foo来实现这种有效的行为: public class MockedFoo implements Foo { private String bazField; @Override public void setBaz(

我有一个简单的获取集界面:

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

我能够在
验证
中使用
with capture
捕获方法参数,但是如何使用相同的输入值设置
期望
?看来你要么能做,要么能做

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



注意:我知道我可以简单地设置一个
实体模型
实例并输入上面的所有代码。然而,我真正的代码要复杂得多,我不想手工制作整个模拟类。

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

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);
}
公共接口Foo{
void setBaz(字符串baz);
字符串getProcessedBaz();
void someOtherMethod();
}
测试中的公共静态类{
字符串doSomething(Foo-Foo){
foo.setBaz(“ABC”);
foo.someOtherMethod();
返回foo.getProcessedBaz();
}
}
@试验
公共文件(mockFoo){
Foo-Foo=新模型(){
字符串baz;
@Mock void setBaz(字符串baz){this.baz=baz;}
@模拟字符串getProcessedBaz(){返回“已处理的”+baz;}
}.getMockInstance();
String res=new ClassUnderTest().doSomething(foo);
资产质量(“已处理的”资产);
}

同样的测试也可以使用JMockit Expectations API(使用
委托
对象)编写,但由于该API用于基于行为的测试(即,当您更关心调用哪些方法而不是对象之间的状态传输时),测试将更加详细。

您可以使用委托来完成此操作。你可以试试这个

要测试的类

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

}

注意:这是从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());
    }
}

谢谢@Rogério。事实上,我今天使用的是
Mockup
(见我问题的结尾)。与显式创建模拟类相比,这种方法似乎没有任何优势。我正在寻找(希望)更紧凑的方法。:)那么您不需要模拟的方法呢,比如上面示例中的
someOtherMethod
?我相信这是一个优势。也就是说,我同意对于方法很少的接口来说,创建一个常规的实现类更简单。我明白了,是的,这绝对是一个优势。我希望用更简单的语法得到更多的答案。如果没有,我将只使用
模型