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



我使用的是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来模拟受保护的方法?如果答案是肯定的,我愿意升级我的版本。

这不是Mockito的问题,而是普通的旧java的问题。从调用方法的位置看,您没有可见性。这就是为什么它是一个编译时问题而不是运行时问题。

几个选项:

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

响应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 protectedMethod() {
            return "You can see me now!";
        }
    }
    @Mock
    MyClassMock myClass = mock(MyClassMock.class);
    @Test
    public void myClassPublicMethodTest() {
        when(myClass.publicMethod()).thenCallRealMethod();
        when(myClass.protectedMethod()).thenReturn("jk!");
    }
}

您可以使用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));
    }
}

使用doReturn()和Junit5的ReflectionSupport,以下内容对我有效。

[注:我在Mockito 3.12.4]上进行了测试

ReflectionSupport.invokeMethod(
        mymock.getClass()
//              .getSuperclass()     // Uncomment this, if the protected method defined in the parent class.
                .getDeclaredMethod("myMethod", String.class, String.class),
        doReturn(myData).when(mymock),
        param1,
        param2);

John B是对的,这是因为你试图测试的方法是受保护的,这不是Mockito的问题。

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

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

  • 什么是反射?它在哪里有用
  • 如何测试具有私有方法、字段或内部类的类

WhiteBox.invokeMethod()非常方便。

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

在春季,您可以将其设置为高优先级,如下所示:

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

覆盖原始bean也是一样的。

相关内容

  • 没有找到相关文章

最新更新