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
가는 길이에요.
의도에 따라 다음을 사용할 수 있습니다.
- 생성자 주입
- 속성 설정기 주입
- 현장 주입
문서의 상세 정보
다음으로 필드 주입의 예를 나타냅니다.
클래스:
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();
}
}
네, 꼭 필요한 경우 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
'programing' 카테고리의 다른 글
vuejs에서 메뉴 외부를 클릭할 경우 드롭다운 메뉴를 숨기는 방법 (0) | 2022.08.31 |
---|---|
Java: 정적 클래스 대 내부 클래스 (0) | 2022.08.31 |
형식 스크립트가 있는 Vue2, 유형에 속성이 없습니다. (0) | 2022.08.30 |
구조 내 구성원의 순서가 중요합니까? (0) | 2022.08.30 |
C 구조체의 기본값 (0) | 2022.08.30 |