簡體   English   中英

JUnit5:將 object 上的每個方法調用轉發到包裝器 function

[英]JUnit5: Forward every method call on object to wrapper function

我有以下情況:

我有一個 class 我想用 JUnit/Mockito 進行測試,但我想添加一些代碼,這些代碼應該在對 object 的每個方法調用中執行。

例如,如果對測試的 class 的調用花費超過特定時間量,我希望測試失敗(忽略與@Timeout類似的功能已經存在,這只是一個簡單的示例)。 到目前為止,我所做的是編寫一個將方法/lambda 作為參數的方法,並做到這一點。 調用如下所示:

Object result = failOnTimeout( () -> testedInstance.calledMethod(x, y) );

這有一個缺點,我需要記住包裝每個方法調用。 有沒有更好的方法來規避這種情況? 我想要的理想行為是這樣的:

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

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

如果有人可以讓我知道是否存在此功能或可以解決我的問題的功能,將不勝感激。

在您的情況下,我看到了一些明顯的解決方案。 假設我們有這樣一個 class:

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

Mockito

首先,您可以使用 Mockito 方法。 並使用org.mockito.stubbing.Answer class 和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);
    }
}

Inheritance

第二個選項是經過測試的 class 的 inheritance。 如果您測試的 class 不是最終的,那么您可以繼承它。 例如:

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

裝飾

或者,如果您測試的 class 是最終的。 你可以裝飾它們:

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

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM