junit5:将对象上的每个方法调用转发给 Package 器函数

mdfafbf1  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(385)

我有以下情况:
我有一个类,我想用junit/mockito测试,但我想添加一些代码,这些代码应该在对该对象的每个方法调用上执行。
例如,如果对被测试类的调用花费的时间超过了特定的时间,我希望测试失败(忽略类似于 @Timeout 已经存在,这只是一个简单的例子)。到目前为止,我所做的是编写一个方法,该方法将method/lambda作为参数并执行此操作。一个电话是这样的: Object result = failOnTimeout( () -> testedInstance.calledMethod(x, y) ); 这样做的缺点是我需要记住 Package 每个方法调用。有没有更好的方法来规避这个问题?我想要的理想行为是这样的:

@BeforeAll
public void setup() {
    testedInstace = new testedClass();
    wrapMethodCall(testedInstance, failOnTimeout);
}

@Test
public void acualTest() {
    Object result = testedInstance.calledMethod(x, y); //Implicitly calls 'failOnTimeout'
    // ...
}

如果有人能让我知道这或一个功能,将解决我的问题存在,我将不胜感激。

hkmswyz6

hkmswyz61#

我在你的情况下看到了一些明显的解决办法。假设我们有这样一个班级:

public class TestedClass {
    public void calledMethod(int x, int y) {
        System.out.println("Hello, Alexander");
    }
}

Mockito

首先,你可以使用mockito方法。使用 org.mockito.stubbing.Answer 类和 Mockito.spy(...) 方法。例如:

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer;

public class TestedClassTestMockitoWay {
    @Test
    void calledMethodTest() {
        TestedClass original = new TestedClass();
        TestedClass spy = Mockito.spy(original);
        Answer<Void> answer = new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocationOnMock) {
                timeoutWrapper(() -> {
                    try {
                        invocationOnMock.callRealMethod();
                    } catch (Throwable ignore) {
                    }
                });
                return null;
            }
            private void timeoutWrapper(Runnable runnable) {
                //todo: timeout implementation
                System.out.println("before");
                runnable.run();
                System.out.println("after");
            }
        };
        doAnswer(answer).when(spy).calledMethod(anyInt(), anyInt());
        spy.calledMethod(1, 2);
    }
}

继承

第二种选择是被测试类的继承。如果您的测试类不是final,那么您可以直接继承它。例如:

import org.junit.jupiter.api.Test;

class TestedClassTestInheritanceWay {
    @Test
    void calledMethodTest() {
        TimeoutTestedClass testedClass = new TimeoutTestedClass();
        testedClass.calledMethod(1, 2);
    }

    private static class TimeoutTestedClass extends TestedClass {
        @Override
        public void calledMethod(int x, int y) {
            timeoutWrapper(() -> super.calledMethod(x, y));
        }

        private void timeoutWrapper(Runnable runnable) {
            //todo: timeout implementation
            System.out.println("before");
            runnable.run();
            System.out.println("after");
        }
    }
}

装饰

或者如果你的考试是期末考试。你可以装饰它们:

import org.junit.jupiter.api.Test;

public class TestedClassTestCompositionWay {

    @Test
    void calledMethodTest() {
        TestedClass original = new TestedClass();
        TimeoutTestedClass testedClass = new TimeoutTestedClass(original);
        testedClass.calledMethod(1, 2);
    }

    private static class TimeoutTestedClass {

        private final TestedClass testedClass;

        private TimeoutTestedClass(TestedClass testedClass) {
            this.testedClass = testedClass;
        }

        public void calledMethod(int x, int y) {
            timeoutWrapper(() -> testedClass.calledMethod(x, y));
        }

        private void timeoutWrapper(Runnable runnable) {
            //todo: timeout implementation
            System.out.println("before");
            runnable.run();
            System.out.println("after");
        }

    }
}

相关问题