Java 使用Mockito时,是否可以在所有答案中添加拦截器?

Java 使用Mockito时,是否可以在所有答案中添加拦截器?,java,mockito,Java,Mockito,假设我的接口方法上有一个验证注释,用于验证输入参数和返回值。 目前(v1.9.5)是否可以告诉Mockito在调用过程中调用这个验证器 背景是通过以违反指定验证器的方式模拟给定接口来防止开发人员编写不切实际的测试 所以我想注册的是 class MyAnswerInterceptor<T> implements AnswerInterceptor<T> { @Override public Answer<T> intercept(final An

假设我的接口方法上有一个验证注释,用于验证输入参数和返回值。 目前(v1.9.5)是否可以告诉Mockito在调用过程中调用这个验证器

背景是通过以违反指定验证器的方式模拟给定接口来防止开发人员编写不切实际的测试

所以我想注册的是

class MyAnswerInterceptor<T> implements AnswerInterceptor<T> {
    @Override
    public Answer<T> intercept(final Answer<T> answer) {
        return new Answer<T>() {
            @Override
            public T answer(InvocationOnMock invocation) throws Throwable {
                validateArguments(invocation);
                T result = answer.answer(invocation);
                validateReturnValue(result);
                return result;
            }
        }
    }
}
类MyAnswerInterceptor实现AnswerInterceptor{
@凌驾
公共答案截取(最终答案){
返回新答案(){
@凌驾
公共T应答(调用锁调用)抛出可丢弃{
validateArguments(调用);
T result=answer.answer(调用);
验证返回值(结果);
返回结果;
}
}
}
}
被要求回答一个给定的问题。 这可能吗?我已经研究了代码,也检查了我是否可以在某个时候侵入(甚至使用反射或类似的方法),但似乎由于实例创建和逻辑的纠缠,很难实现我想要的(例如
MockHandler MockHandler=new MockHandlerFactory().create(设置)
使得在不修补和部署整个东西的情况下,不可能连接并在顶部放置自定义内容……)


如果您有任何见解,我们将不胜感激:-)

您可以通过创建自定义

MockMaker是一个扩展点,它可以使用自定义动态代理并避免使用默认的cglib/asm/objenesis实现

我们的自定义实现将所有复杂的内容委托给默认的
MockMaker
CglibMockMaker
。它通过注册
设置
参数仅“修饰”方法。当
调用
完成后,允许使用调用
validateArguments
validateReturnValue
时,将通知此侦听器

import org.mockito.internal.creation.CglibMockMaker;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.MockHandler;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockMaker;

public class ValidationMockMaker implements MockMaker {
    private final MockMaker delegate = new CglibMockMaker();

    public ValidationMockMaker() {
    }
    @Override
    public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
        settings.getInvocationListeners().add(new InvocationListener() {

            @Override
            public void reportInvocation(MethodInvocationReport methodInvocationReport) {
                Invocation invocation = (Invocation) methodInvocationReport.getInvocation();
                validateArguments(invocation.getArguments());
                validateReturnValue(methodInvocationReport.getReturnedValue());
            }
        });
        return delegate.createMock(settings, handler);
    }

    @Override
    public MockHandler getHandler(Object mock) {
        return delegate.getHandler(mock);
    }

    @Override
    public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) {
        delegate.resetMock(mock, newHandler, settings);
    }

    protected void validateArguments(Object... arguments) {
//        Arrays.stream(arguments).forEach(Objects::requireNonNull);
    }

    private void validateReturnValue(Object result) {
//        Objects.requireNonNull(result);
    }
}
包含我们的MockMaker类名:

ValidationMockMaker

请参阅javadoc中的一节。

找到了一个有效的解决方案,即编写我自己的
when(T methodCall)
方法,在其中我委托给
Mockito.when
,然后将ongoingstubing包装到Javassist代理中,并捕获所有
thenBlubb(…)
方法将相应的答案包装到我的拦截器中并返回OngoingStubing代理。无论如何,这肯定不是最整洁的方式,所以如果有人知道一种更漂亮的方式,我仍然愿意接受建议;-)(尤其是处理所有
thenBlubb(…)
方法很糟糕,每次升级都需要进一步注意…)此外,您的解决方案对于void方法等方法也不起作用,在void方法中,您需要doXxx/when语法来代替when/thenXxx语法。除非您为每个doXxx方法制作自己的版本。嗨!您希望将一些非常复杂的逻辑混合到简单的单元测试中。为什么不把验证器本身与使用它的逻辑分开进行单元测试,然后在集成测试中对其进行整体测试呢?嗯,我不知道逻辑是否那么复杂,答案是四行。。。其想法是应用类似契约式设计的东西,通过在生产代码中的注释指定“契约”,然后使用上述技术确保开发人员以遵守契约的方式模拟组件。如果这是一个好主意,我不知道,但我已经不止一次遇到错误假设的单元测试(以一种在实际生产代码中不会发生的方式进行模拟)…太棒了,这看起来正是我需要的,非常感谢!!!我会尽快尝试这种方法:-)
ValidationMockMaker