如何使用Mockito模拟受保护的方法?

时间:2015-12-04 16:16:54

标签: junit mocking mockito protected

我正在使用Mockito 1.9.5。如何模拟受保护方法返回的内容?我有这种受保护的方法......

protected JSONObject myMethod(final String param1, final String param2)
{
…
}

但是,当我尝试在JUnit中执行此操作时:

    final MyService mymock = Mockito.mock(MyService.class, Mockito.CALLS_REAL_METHODS);        
    final String pararm1 = “param1”;
    Mockito.doReturn(myData).when(mymock).myMethod(param1, param2);

在最后一行,我收到编译错误“方法'myMethod'不可见。”我如何使用Mockito来模拟受保护的方法?如果这是答案,我愿意升级我的版本。

6 个答案:

答案 0 :(得分:26)

这不是Mockito的问题,而是普通的旧java。从您调用方法的地方开始,您就无法看到。这就是为什么它是编译时问题而不是运行时问题。

几个选项:

  • 在与模拟类
  • 相同的包中声明您的测试
  • 如果可以
  • ,则更改方法的可见性
  • 创建一个扩展模拟类的本地(内部)类,然后模拟这个本地类。由于该类是本地的,因此您可以看到该方法。

答案 1 :(得分:7)

回应John B的回答中对选项3的代码样本的请求:

public class MyClass {
    protected String protectedMethod() {
        return "Can't touch this";
    }
    public String publicMethod() {
        return protectedMethod();
    }
}
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    class MyClassMock extends MyClass {
        @Override
        public String protectedFunction() {
            return "You can see me now!";
        }
    }

    @Mock
    MyClassMock myClass = mock(MyClassMock.class);

    @Test
    public void myClassPublicFunctionTest() {
        when(myClass.publicFunction()).thenCallRealMethod();
        when(myClass.protectedFunction()).thenReturn("jk!");
    }
}

答案 2 :(得分:1)

John B是对的,这是因为您尝试测试的方法受到保护,这对Mockito来说不是问题。

他列出的另一个选项是使用反射来访问该方法。这将允许您避免更改正在测试的方法,并避免更改用于编写测试的模式,以及存储这些测试的位置。我自己必须做一些测试,我不允许更改现有的代码库,其中包含大量需要进行单元测试的私有方法。

这些链接解释了Reflection以及如何使用它,所以我将链接到它们而不是复制:

答案 3 :(得分:0)

WhiteBox.invokeMethod()可以很方便。

答案 4 :(得分:0)

您可以使用Spring的ReflectionTestUtils照原样使用您的类,而无需为测试而更改它或将其包装在另一个类中。

public class MyService {
    protected JSONObject myProtectedMethod(final String param1, final String param2) {
        return new JSONObject();
    }

    public JSONObject myPublicMethod(final String param1) {
        return new JSONObject();
    }
}

然后在测试中

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private MyService myService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(myService.myPublicMethod(anyString())).thenReturn(mock(JSONObject.class));
        when(ReflectionTestUtils.invokeMethod(myService, "myProtectedMethod", anyString(), anyString())).thenReturn(mock(JSONObject.class));
    }

}

答案 5 :(得分:0)

public class Test extend TargetClass{
    @Override
    protected Object method(...) {
        return [ValueYouWant];
    }  
}

在Spring中,您可以像这样将其设置为高优先级:

@TestConfiguration
public class Config {

    @Profile({"..."})
    @Bean("...")
    @Primary  // <------ high-priority
    public TargetClass TargetClass(){
        return new TargetClass() {
            @Override
            protected WPayResponse validate(...)  {
                return null;
            }
        };
    }
}

覆盖原始bean相同。