나는 Mockito를 처음 사용합니다.
아래 클래스가 주어지면 Mockito를 사용하여 someMethod
호출 한 후 정확히 한 번 호출 되었는지 어떻게 확인할 수 foo
있습니까?
public class Foo
{
public void foo(){
Bar bar = new Bar();
bar.someMethod();
}
}
다음과 같은 확인 전화를하고 싶습니다.
verify(bar, times(1)).someMethod();
bar
의 조롱 된 인스턴스는 어디에 있습니까 Bar
?
답변
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가 코드 디자인을 주도 할 수있는 방법의 예입니다.
답변
고전적인 반응은 “그렇지 않다”입니다. Foo
내부 API가 아닌 의 공개 API를 테스트합니다 .
영향을받는 Foo
개체 (또는 환경의 다른 개체)의 동작이 foo()
있습니까? 그렇다면 테스트하십시오. 그렇지 않은 경우 방법은 무엇을합니까?
답변
DI 또는 공장을 사용하지 않으려는 경우. 약간 까다로운 방식으로 수업을 리팩토링 할 수 있습니다.
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 클래스를 가져올 필요가 없습니다.
물론 단점은 호출자가 막대 객체를 설정할 수 있다는 것입니다.
도움이 되길 바랍니다.
답변
예제 코드를 사용하는 솔루션 PowerMockito.whenNew
- mockito-all 1.10.8
- 파워 코어 1.6.1
- powermock- 모듈 -junit4 1.6.1
- powermock-api-mockito 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();
}
}
답변
나는 Mockito 생각 @InjectMocks
가 갈 길이 합니다.
당신의 의도에 따라 다음을 사용할 수 있습니다.
- 생성자 주입
- 속성 세터 주입
- 필드 주입
문서에 대한 추가 정보
아래는 필드 주입의 예입니다.
클래스:
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();
}
}
답변
예, 정말로 원하거나해야 할 경우 PowerMock을 사용할 수 있습니다. 이것은 최후의 수단으로 간주되어야합니다. PowerMock을 사용하면 호출에서 생성자로 모의를 반환 할 수 있습니다. 그런 다음 모의에서 확인하십시오. 즉, csturtz는 “올바른”답변입니다.
새로운 객체의 모의 구성에 대한 링크는 다음과 같습니다.
답변
또 다른 간단한 방법은 bar.someMethod ()에 로그 문을 추가 한 다음 테스트가 실행될 때 해당 메시지를 볼 수 있는지 확인하십시오. 여기의 예제를 참조하십시오 : 로거의 메시지에 JUnit assert를 수행하는 방법
Bar.someMethod ()가 인 경우 특히 유용합니다 private
.