EasyMockユニットのテスト中に関連クラスをシミュレートした例

3563 ワード

ユニットテストの過程で、1つのクラスの機能が正常かどうかをテストすることを望んでいますが、1つのクラスでは他のクラスを参照することが多く、1つのクラスをテストすると同時に他のクラス関連もテストすることはできません.結果は良好で、1つのテストはターゲットクラスだけでなく他のクラスもテストしたように見えますが、このようなクロステストは致命的な問題を招き、ユニットテストは単一のクラスをテストしなくなり、1つのクラスに問題が発生すると複数のユニットテストに影響し、同じテストに失敗してもどのクラスに問題が発生するか分かりません.ユニットテストは統合テストとなり、ユニットテストの意味を失った. 
したがって、合理的なユニットテストはクラスがテストを書くべきで、関連する他の参照クラスはどうしますか?EasyMockはそのために生まれ、関連するクラスの動作をシミュレートすることができます.具体的には、クラスは主に所有するメソッドの動作であり、EasyMockは、メソッドがどのようなパラメータを入力してどのような値を返すか、プログラムで何回呼び出すかなどを設定することができる.これにより、ユニットテストは本当の意味の「ユニット」テストであり、テストコードをより正確にすることができます.
簡単な例を次に示します.
テスト対象クラス:

public class BaseAvailabilityService implements AvailabilityService {
	
	
	private IConvert convert;
	private IService service;
	private IProfileService profile;
	
	@Override
	public Availability getAvailability(AvailabilityCriteria criteria, Contract contract) {
		final HotelSearchCriteria hsc = (HotelSearchCriteria) criteria.getCriteria();
		final ChannelHotelMapping hotelMapping = profile.getChannelHotelMapping(contract.getChannelCode(), hsc.getUniqueHotelCode());
		
		GetAvailRS avail = service.getAvailability(hotelMapping.getChannel().getAccount(), convert.toGetAvailRQ(criteria, hotelMapping));
		return convert.toAvailability(avail, criteria.getGuestCount().getAdultCount(), hotelMapping, null);
	}
	@Required
	public void setConvert(IStarwoodConvert convert) {
		this.convert = convert;
	}

	@Required
	public void setService(IStarwoodService service) {
		this.service = service;
	}
	@Required
	public void setProfile(IProfileService profile) {
		this.profile = profile;
	}

}
テストコード:

public class AvailabilityServiceTest {
	
	private BaseAvailabilityService availService = new BaseAvailabilityService();
	private IConvert convert;
	private IService service;
	private IProfileService profile;
	@Before
	public void startup(){
		convert = EasyMock.createMock(IConvert.class);
		service = EasyMock.createMock(IService.class);
		profile = EasyMock.createMock(IProfileService.class);
		availService.setConvert(convert);
		availService.setProfile(profile);
		availService.setService(service);
	}
	@Test
	public void testGetAvailability(){
		ChannelHotelMapping mapping = new ChannelHotelMapping();
		mapping.setChannel(new Channel());
		
		AvailabilityCriteria availCriteria = new AvailabilityCriteria();
		availCriteria.setCriteria(new HotelSearchCriteria());
		availCriteria.setGuestCount(new GuestCount());
		
		GetAvailRQ getAvailRQ = new GetAvailRQ();
		
		EasyMock.expect(profile.getChannelHotelMapping(null, null)).andReturn(mapping);
		EasyMock.expect(service.getAvailability(new Account(null,null), getAvailRQ)).andReturn(new GetAvailRS());
		EasyMock.expect(convert.toAvailability(new GetAvailRS(), null,mapping, null)).andReturn(new Availability());
		EasyMock.expect(convert.toGetAvailRQ(availCriteria, mapping)).andReturn(getAvailRQ);
		EasyMock.replay(profile,service,convert);
		availService.getAvailability(availCriteria, new Contract());
		EasyMock.verify(profile,service,convert);
	}
}

以上の例では、Mockのメソッドにはパラメータと戻り値がありますが、パラメータがあっても戻り値がないメソッドであれば、まったくシミュレーションできません.シミュレーション呼び出しの次の行でexpectLastCall()を実行します.
mokedObject.someFunction(sameObject);
EasyMock.expectLastCall();

もう1つの問題は、どの値を入力しても特定の値を返す方法を設定したい場合、どのように設定しますか?パラメータはEasyMockを使用することができる.isA(SomeObject.class)では、SomeObjectのインスタンスであれば、以下のようなプリセット動作が実行されます.
mokedObject.someFunction(EasyMock.isA(Object.class));