programing

Mockito : 메서드 내에서 생성된 개체에서 메서드가 호출되었는지 확인하는 방법

prostudy 2022. 8. 31. 21:35
반응형

Mockito : 메서드 내에서 생성된 개체에서 메서드가 호출되었는지 확인하는 방법

저는 모키토에 처음 왔어요.

아래 클래스에서 Mockito를 사용하여 다음 내용을 검증하려면 어떻게 해야 합니까?someMethod그 후 정확히 한 번 호출되었다foo호출되었습니까?

public class Foo
{
    public void foo(){
        Bar bar = new Bar();
        bar.someMethod();
    }
}

아래와 같은 확인 전화를 걸고 싶습니다.

verify(bar, times(1)).someMethod();

어디에bar의 조롱의 일례입니다.Bar.

의존 관계 주입

막대 인스턴스 또는 막대 인스턴스 작성에 사용되는 팩토리(또는 기타 483 방법 중 하나)를 주입하는 경우 테스트를 수행하는 데 필요한 액세스 권한이 있습니다.

공장에서의 예:

Foo 클래스는 다음과 같이 작성됩니다.

public class Foo {
  private BarFactory barFactory;

  public Foo(BarFactory factory) {
    this.barFactory = factory;
  }

  public void foo() {
    Bar bar = this.barFactory.createBar();
    bar.someMethod();
  }
}

테스트 방법에서는 다음과 같이 BarFactory를 주입할 수 있습니다.

@Test
public void testDoFoo() {
  Bar bar = mock(Bar.class);
  BarFactory myFactory = new BarFactory() {
    public Bar createBar() { return bar;}
  };
  
  Foo foo = new Foo(myFactory);
  foo.foo();

  verify(bar, times(1)).someMethod();
}

보너스: 이것은 TDD(Test Driven Development)가 코드 설계를 추진하는 방법의 예입니다.

전형적인 대답은 "넌 몰라"입니다.의 퍼블릭 API를 테스트합니다.Foo내부가 아니라

의 동작이 있습니까?Foo영향을 받는 오브젝트(또는 환경 내의 다른 오브젝트)foo()그렇다면 테스트해 보십시오.그렇지 않은 경우 이 방법은 어떤 역할을 합니까?

DI 또는 Factories를 사용하지 않으시면 됩니다.조금 까다로운 방법으로 수업을 리팩터링할 수 있습니다.

public class Foo {
    private Bar bar;

    public void foo(Bar bar){
        this.bar = (bar != null) ? bar : new Bar();
        bar.someMethod();
        this.bar = null;  // for simulating local scope
    }
}

그리고 당신의 시험 수업:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock Bar barMock;
    Foo foo;

    @Test
    public void testFoo() {
       foo = new Foo();
       foo.foo(barMock);
       verify(barMock, times(1)).someMethod();
    }
}

그러면 foo 메서드를 호출하는 클래스는 다음과 같이 수행합니다.

public class thirdClass {

   public void someOtherMethod() {
      Foo myFoo = new Foo();
      myFoo.foo(null);
   }
}

메서드를 이렇게 호출할 때 알 수 있듯이 foo 메서드를 호출하는 다른 클래스에서 Bar 클래스를 가져올 필요가 없습니다.이러한 클래스는 원하는 메서드일 수 있습니다.

물론 단점은 발신자가 Bar Object를 설정할 수 있도록 하는 것입니다.

도움이 됐으면 좋겠다.

모키토라고 생각합니다.@InjectMocks가는 길이에요.

의도에 따라 다음을 사용할 수 있습니다.

  1. 생성자 주입
  2. 속성 설정기 주입
  3. 현장 주입

문서의 상세 정보

다음으로 필드 주입의 예를 나타냅니다.

클래스:

public class Foo
{
    private Bar bar = new Bar();

    public void foo() 
    {
        bar.someMethod();
    }
}

public class Bar
{
    public void someMethod()
    {
         //something
    }
}

테스트:

@RunWith(MockitoJUnitRunner.class)
public class FooTest
{
    @Mock
    Bar bar;

    @InjectMocks
    Foo foo;

    @Test
    public void FooTest()
    {
        doNothing().when( bar ).someMethod();
        foo.foo();
        verify(bar, times(1)).someMethod();
    }
}

예제 코드의 솔루션:PowerMockito.whenNew

  • mockito - all 1.10.8
  • Powermock 코어 1.6.1
  • powermock-syslog-junit4 1.6.1
  • powermock-api-paramito 1.6.1
  • Junit 4.12

FooTest.java

package foo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

//Both @PrepareForTest and @RunWith are needed for `whenNew` to work 
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Foo.class })
public class FooTest {

    // Class Under Test
    Foo cut;

    @Mock
    Bar barMock;

    @Before
    public void setUp() throws Exception {
        cut = new Foo();

    }

    @After
    public void tearDown() {
        cut = null;

    }

    @Test
    public void testFoo() throws Exception {

        // Setup
        PowerMockito.whenNew(Bar.class).withNoArguments()
                .thenReturn(this.barMock);

        // Test
        cut.foo();

        // Validations
        Mockito.verify(this.barMock, Mockito.times(1)).someMethod();

    }

}

JUnit 출력 JUnit 출력

네, 꼭 필요한 경우 PowerMock을 사용할 수 있습니다.이것은 최후의 수단으로 여겨져야 한다.PowerMock을 사용하면 콜에서 컨스트럭터로 모크를 반환할 수 있습니다.그런 다음 모의 검증을 수행합니다.즉, csturtz가 정답입니다.

객체의 모의 구성 링크입니다.

또 다른 간단한 방법은 bar.someMethod()에 log 문을 추가하고 테스트 실행 시 위의 메시지가 표시되는지 확인하는 것입니다.다음 예를 참조하십시오.로거 메시지에서 JUnit 아사트를 실행하는 방법

은 Bar가 "Bar.someMethod()"일 때 편리합니다.private.

저는 오늘 이 문제가 있어서 Power Mock이나 다른 것을 사용하고 싶지 않았습니다.그냥 특정 메서드가 호출되었는지 확인하는 테스트를 만들고 싶었어요.저는 이 게시물을 찾았는데 아무도 이 접근법에 대해 언급하지 않았다는 것을 알게 되었습니다.

의존관계를 늘리지 않고 이를 실현하는 방법 중 하나는 매우 낮은 수준의 기술이지만 다음과 같이 작동합니다.

@Test
public void testSomeMethodIsCalledOnce() throws Exception {
    final AtomicInteger counter = new AtomicInteger(0);
    Mockito.when(someObject.theMethodIWant(anyString()))
        .then((Answer<ReturnValue>) __ -> {
            teller.incrementAndGet();
            return theExpectedAnswer;
        });
    theObjectUnderTest.theMethod(someTestValue);

    assertEquals(1, teller.get());
}

이것은 매우 간단하며 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.내가 원하는 방법이 (여기에서는 조롱을 받고 있다)라고 불리면, 이것을 실행해 주세요.그 중에는 ATOMIC Integer에 대한 incrementAndGet 호출도 있습니다.여기서 int[]를 사용해도 좋지만 내 생각에는 그렇게 명확하지 않다.우리는 단지 최종적인 것을 사용하고 있을 뿐이고, 그것을 증가시킬 수 있습니다.그게 우리가 사용하는 람다의 한계야.

조금 조잡하지만, 간단하고 간단한 문제만으로 일을 끝낼 수 있습니다.적어도 람다와 모키토를 알고 있다면 말이야

언급URL : https://stackoverflow.com/questions/9841623/mockito-how-to-verify-method-was-called-on-an-object-created-within-a-method

반응형