는이 같은 구조를 가지고 : 예외를 throw하기 위해 void 메소드를 조롱 할 수 있습니까?
public class CacheWrapper {
private Map<Object, Object> innerMap;
public CacheWrapper() {
//initialize the innerMap with an instance for an in-memory cache
//that works on external server
//current implementation is not relevant for the problem
innerMap = ...;
}
public void putInSharedMemory(Object key, Object value) {
innerMap.put(key, value);
}
public Object getFromSharedMemory(Object key) {
return innerMap.get(key);
}
}
그리고 내 클라이언트 클래스는 (당신은 다음과 같습니다 말할 수) :
public class SomeClient {
//Logger here, for exception handling
Logger log = ...;
private CacheWrapper cacheWrapper;
//getter and setter for cacheWrapper...
public Entity getEntity(String param) {
Entity someEntity = null;
try {
try {
entity = cacheWrapper.getFromSharedMemory(param);
} catch (Exception e) {
//probably connection failure occurred here
log.warn("There was a problem when getting from in-memory " + param + " key.", e);
}
if (entity == null) {
entity = ...; //retrieve it from database
//store in in-memory cache
try {
cacheWrapper.put(param, entity);
} catch (Exception e) {
//probably connection failure occurred here
log.warn("There was a problem when putting in in-memory " + param + " key.", e);
}
}
} catch (Exception e) {
logger.error(".......", e);
}
return entity;
}
}
내가 SomeClient#getEntity
방법에 대한 단위 테스트를 작성하고있는거야 모든 시나리오를 다룰 수 있습니다. 예를 들어, cacheWrapper
에 의해 던진 예외가있는 시나리오를 다루어야합니다. 내가 따르는 접근법은 CacheWrapper
클래스의 모의 객체를 만들고 CacheWrapper
클래스의 메소드를 RuntimeException
을 던집니다. SomeClient
의 인스턴스에서이 모의 객체를 설정하고 Someclient#getEntity
을 테스트합니다. 문제는 void
이기 때문에 putInSharedMemory
메서드를 모의하려고 할 때입니다. 나는 이것을하기 위해 많은 방법을 시도했지만 그 중 누구도 일하지 않습니다. 프로젝트의 PowerMock 및 EasyMock에 대한 종속성이 있습니다.
EasyMock.<Void>expect
사용 : 여기 내 시도이다. 이로 인해 컴파일러 오류가 발생했습니다.스터브하려고 시도
CacheWrapper#putInSharedMemory
. 일을하지 않았다 때문에이 오류 메시지와 함께 예외를 제기 : 프로젝트에java.lang.AssertionError: Unexpected method call putInSharedMemory("foo", [email protected])
추가 Mockito 의존성이
PowerMockito
클래스의 기능을 활용할 수 있습니다. 그러나 EasyMock과 통합되지 않기 때문에 예외가 발생했습니다.java.lang.ClassCastException: org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl cannot be cast to org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl
여기이 단위 테스트 샘플에 대한 코드이다 : 그것은 제 3 자 라이브러리에서 오기 때문에
@Test
public void getEntityWithCacheWrapperException() {
CacheWrapper cacheWrapper = mockThrowsException();
SomeClient someClient = new SomeClient();
someClient.setCacheWrapper(cacheWrapper);
Entity entity = someClient.getEntity();
//here.....................^
//cacheWrapper.putInSharedMemory should throw an exception
//start asserting here...
}
//...
public CacheWrapper mockThrowsException() {
CacheWrapper cacheWrapper = PowerMock.createMock(CacheWrapper.class);
//mocking getFromSharedMemory method
//this works like a charm
EasyMock.expect(cacheWrapper.getFromSharedMemory(EasyMock.anyObject()))
.andThrow(new RuntimeException("This is an intentional Exception")).anyTimes();
//mocking putInSharedMemory method
//the pieces of code here were not executed at the same time
//instead they were commented and choose one approach after another
//attempt 1: compiler exception: <Void> is not applicable for <void>
EasyMock.<Void>expect(cacheWrapper.putInSharedMemory(EasyMock.anyObject(), EasyMock.anyObject()))
.andThrow(new RuntimeException("This is an intentional Exception")).anyTimes();
//attempt 2: stubbing the method
//exception when executing the test:
//Unexpected method call putInSharedMemory("foo", [email protected])
Method method = PowerMock.method(CacheWrapper.class, "putInSharedMemory", Object.class, Object.class);
PowerMock.stub(method).toThrow(new RuntimeException("Exception on purpose."));
//attempt 3: added dependency to Mockito integrated to PowerMock
//bad idea: the mock created by PowerMock.createMock() belongs to EasyMock, not to Mockito
//so it breaks when performing the when method
//exception:
//java.lang.ClassCastException: org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl
//cannot be cast to org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl
//at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:54)
PowerMockito.doThrow(new RuntimeException("Exception on purpose."))
.when(cacheWrapper).putInSharedMemory(EasyMock.anyObject(), EasyMock.anyObject());
PowerMock.replay(cacheWrapper);
return cacheWrapper;
}
내가 CacheWrapper
의 구현을 변경할 수 없습니다이 제기 된 예외입니다. 또한 SomeClient#getEntity
에서 테스트를 수행 중이므로 EasyMock#getLastCall
을 사용할 수 없습니다.
어떻게 이것을 극복 할 수 있습니까? 같은
왜 전혀 PowerMockito 필요합니까? 테스트 된 클래스 중 마지막 클래스는 하나도 없으므로 인스턴스화 된 인스턴스 (sp_can_ 스텁 스파이)를 통해 단지 'spy()'를 사용할 수 있습니다. 또한, .replay()는 어디에서 왔습니까? – fge
@fge 필자는 순수 단위 테스트가 아닌 통합 테스트를 작성하기 때문에 이러한 프레임 워크를 사용하는 데 익숙하지 않습니다. 이'spy()'메소드 나 관련 문서에 대해 더 자세히 설명해 주시겠습니까? –
모두 테스트 코드는 모두 정말 기괴합니다. 당신은 easockock과 (전원) mockito를 사용하는 것처럼 보입니다 ... 어떤 이유가 있습니까? – fge