your programing

Mockito로 void 메서드를 모의하는 방법

lovepro 2020. 9. 28. 09:49
반응형

Mockito로 void 메서드를 모의하는 방법


void 반환 유형으로 메서드를 모의하는 방법은 무엇입니까?

관찰자 패턴을 구현했지만 방법을 모르기 때문에 Mockito로 조롱 할 수 없습니다.

그리고 인터넷에서 예를 찾으려고했지만 성공하지 못했습니다.

내 수업은 다음과 같습니다.

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal,Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private string state;
    //setter getter state
} 

public class WorldTest implements Listener {

    @Test public void word{
    World  w= mock(World.class);
    w.addListener(this);
    ...
    ...

    }
}

interface Listener {
    void doAction();
}

시스템은 모의로 트리거되지 않습니다. = (위에서 언급 한 시스템 상태를 보여주고 싶습니다. 그리고 그들에 따라 주장합니다.


Mockito API 문서를 살펴보십시오 . 링크 된 문서 (포인트의 # 12)를 언급으로 당신이 중 하나를 사용할 수 있습니다 doThrow(), doAnswer(), doNothing(), doReturn()Mockito 프레임 워크의 메서드의 가족은 무효 방법을 조롱합니다.

예를 들면

Mockito.doThrow(new Exception()).when(instance).methodName();

또는 후속 행동과 결합하고 싶다면

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

당신이 세터를 조롱보고있는 것을 가정하면 setState(String s)세계 아래 수업은 코드가 사용 된 것입니다 doAnswer을 조롱하는 방법 setState.

World  mockWorld = mock(World.class); 
doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      System.out.println("called with arguments: " + Arrays.toString(args));
      return null;
    }
}).when(mockWorld).setState(anyString());

나는 그 질문에 대한 더 간단한 대답을 찾았다 고 생각합니다. 단지 하나의 메서드에 대한 실제 메서드를 호출하는 것입니다 (보이드 리턴이 있더라도) 다음과 같이 할 수 있습니다.

Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();

또는 다음과 같이 해당 클래스의 모든 메서드에 대해 실제 메서드를 호출 할 수 있습니다.

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);

@sateesh가 말한 것에 덧붙여서, 테스트가 호출하는 것을 막기 위해 void 메서드를 모의하고 싶을 때 다음과 같이 사용할 수 있습니다 Spy.

World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();

테스트를 실행하려면 spy개체가 아닌 개체 에서 테스트의 메서드를 호출해야 world합니다. 예를 들면 :

assertEquals(0,spy.methodToTestThatShouldReturnZero());

소위 문제의 해결책은 사용하는 것입니다 spy Mockito.spy (...) 대신 mock Mockito.mock (..)를 .

Spy enables us to partial mocking. Mockito is good at this matter. Because you have class which is not complete, in this way you mock some required place in this class.


First of all: you should always import mockito static, this way the code will be much more readable (and intuitive):

import static org.mockito.Mockito.*;

For partial mocking and still keeping original functionality on the rest mockito offers "Spy".

You can use it as follows:

private World world = spy(World.class);

To eliminate a method from being executed you could use something like this:

doNothing().when(someObject).someMethod(anyObject());

to give some custom behaviour to a method use "when" with an "thenReturn":

doReturn("something").when(this.world).someMethod(anyObject());

For more examples please find the mockito samples in the doc.


How to mock void methods with mockito - there are two options:

  1. doAnswer - If we want our mocked void method to do something (mock the behavior despite being void).
  2. doThrow - Then there is Mockito.doThrow() if you want to throw an exception from the mocked void method.

Following is an example of how to use it (not an ideal usecase but just wanted to illustrate the basic usage).

@Test
public void testUpdate() {

    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] arguments = invocation.getArguments();
            if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {

                Customer customer = (Customer) arguments[0];
                String email = (String) arguments[1];
                customer.setEmail(email);

            }
            return null;
        }
    }).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

    //some asserts
    assertThat(customer, is(notNullValue()));
    assertThat(customer.getEmail(), is(equalTo("new@test.com")));

}

@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {

    doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

}
}

You could find more details on how to mock and test void methods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)


Adding another answer to the bunch (no pun intended)...

You do need to call the doAnswer method if you can't\don't want to use spy's. However, you don't necessarily need to roll your own Answer. There are several default implementations. Notably, CallsRealMethods.

In practice, it looks something like this:

doAnswer(new CallsRealMethods()).when(mock)
        .voidMethod(any(SomeParamClass.class));

Or:

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
        .voidMethod(any(SomeParamClass.class));

In Java 8 this can be made a little cleaner, assuming you have a static import for org.mockito.Mockito.doAnswer:

doAnswer(i -> {
  // Do stuff with i.getArguments() here
  return null;
}).when(*mock*).*method*(*methodArguments*);

The return null; is important and without it the compile will fail with some fairly obscure errors as it won't be able to find a suitable override for doAnswer.

For example an ExecutorService that just immediately executes any Runnable passed to execute() could be implemented using:

doAnswer(i -> {
  ((Runnable) i.getArguments()[0]).run();
  return null;
}).when(executor).execute(any());

I think your problems are due to your test structure. I've found it difficult to mix mocking with the traditional method of implementing interfaces in the test class (as you've done here).

If you implement the listener as a Mock you can then verify the interaction.

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

This should satisfy you that the 'World' is doing the right thing.

참고URL : https://stackoverflow.com/questions/2276271/how-to-mock-void-methods-with-mockito

반응형