반응형

아래와 같이 간단한 클래스가 있다고 가정해보자.

 

package com.example.mockedstaticunittest;

public class Calculator {
    public static int add(int x, int y) {
        return x + y;
    }

    public int sub(int x, int y) {
        return x - y;
    }
}

 

해당 코드의 sub를 테스트를 하면 아래와 같다.

    @Test
    public void execute_sub() {
        Calculator calculator = new Calculator();

        // when
        int sub = calculator.sub(20, 10);

        // then
        assertEquals(sub, 10);
    }
Process finished with exit code 0

 

하지만 static인 add를 테스트 하면 아래와 같아진다.

    @Test
    public void execute_add() {
        int a = 1, b = 2;
        when(Calculator.add(a, b)).thenReturn(a + b);

        int sum = Calculator.add(a, b);

        assertEquals(a + b, sum);
    }
org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.


	at com.example.mockedstaticunittest.CalculatorTest.execute_add(CalculatorTest.java:12)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

 

static 메서드를 테스트 할 수 없는 상황이 왔고 이를 해결하기 위해 이번에는 Mockito를 이용하여 static method를 해결하는 방법을 알아보고자 한다.

 

 

asolntsev.github.io/en/2020/07/11/mockito-static-methods/

 

Mockito can mock static methods! · Andrei Solntsev

Mockito can mock static methods! 11 Jul 2020 Hot news! Mockito just released version 3.4.0 which can now mock static methods. Before 3.4.0, Mockito could not mock static methods. It could only mock non-static methods. Though, PowerMock could. But PowerMock

asolntsev.github.io

 

우선 build.gradle에서 dependency에 testImplementation('org.mockito:mockito-inline:3.4.0')를 추가해준다.

 

3.4.0버전부터 MockedStatic라는 새로운 기능이 들어감으로써 우리는 PowerMock가 아닌 Mockito를 이용하여서도 static method를 테스트할 수 있게 되었다.

 

아래와 같이 MockedStatic객체를 선언한다.

private static MockedStatic<Calculator> mCalculator;

 

그리고 해당 MockedStatic를 mockStatic 메서드를 이용하여 beforeClass에서 모킹하고 afterClass에서 해제해준다.

    @BeforeClass
    public static void beforeClass() {
        mCalculator = mockStatic(Calculator.class);
    }

    @AfterClass
    public static void afterClass() {
        mCalculator.close();
    }

 

다시 static add method를 테스트해준다. 이때 Calculator.add(anyInt(), anyInt()).thenReturn(a+b)을 이용하여 해당 static method를 모킹해주면 이제 해당 스태틱 메서드를 사용할 수 있게 된다.

    @Test
    public void execute_add() {
        int a = 1, b = 2;
        when(Calculator.add(anyInt(), anyInt())).thenReturn(a + b);

        int sum = Calculator.add(a, b);

        assertEquals(a + b, sum);
    }

 

아래는 전체 코드이다.

package com.example.mockedstaticunittest;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.MockedStatic;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class CalculatorTest {
    private static MockedStatic<Calculator> mCalculator;

    @BeforeClass
    public static void beforeClass() {
        mCalculator = mockStatic(Calculator.class);
    }

    @AfterClass
    public static void afterClass() {
        mCalculator.close();
    }

    @Test
    public void execute_add() {
        int a = 1, b = 2;
        when(Calculator.add(anyInt(), anyInt())).thenReturn(a + b);

        int sum = Calculator.add(a, b);

        assertEquals(a + b, sum);
    }
}

 

반응형