aryaxt의 WebService 응답 맨 위에 다른 테스트에서 다른 결과를 얻을 수있는 약간의 트릭이 있습니다. 먼저
, 당신은 바로 테스트 TestConfiguration.h
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
void MethodSwizzle(Class c, SEL orig, SEL new);
@interface TestConfiguration : NSObject
@property(nonatomic,strong) NSMutableDictionary *results;
+ (TestConfiguration *)sharedInstance;
-(void)setNextResult:(NSObject *)result
forCallToObject:(NSObject *)object
selector:(SEL)selector;
-(NSObject *)getResultForCallToObject:(NSObject *)object selector:(SEL)selector;
@end
TestConfiguration.m
#import "TestConfiguration.h"
void MethodSwizzle(Class c, SEL orig, SEL new) {
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
};
@implementation TestConfiguration
- (id)init
{
self = [super init];
if (self) {
self.results = [[NSMutableDictionary alloc] init];
}
return self;
}
+ (TestConfiguration *)sharedInstance
{
static TestConfiguration *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[TestConfiguration alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
-(void)setNextResult:(NSObject *)result
forCallToObject:(NSObject *)object
selector:(SEL)selector
{
NSString *className = NSStringFromClass([object class]);
NSString *selectorName = NSStringFromSelector(selector);
[self.results setObject:result
forKey:[[className stringByAppendingString:@":"] stringByAppendingString:selectorName]];
}
-(NSObject *)getResultForCallToObject:(NSObject *)object selector:(SEL)selector
{
NSString *className = NSStringFromClass([object class]);
NSString *selectorName = NSStringFromSelector(selector);
return [self.results objectForKey:[[className stringByAppendingString:@":"] stringByAppendingString:selectorName]];
}
@end
전에, 원하는 답을 저장하는 데 사용됩니다 싱글 객체가 필요 그런 다음 모의 메서드를 정의하기 위해 "모의"범주를 정의합니다.
,
#import "MyWebService+Mock.h"
#import "TestConfiguration.h"
@implementation MyWebService (Mock)
-(void)mockFetchEntityWithId:(NSNumber *)entityId
success:(void (^)(Entity *entity))success
failure:(void (^)(NSError *error))failure
{
Entity *response = (Entity *)[[TestConfiguration sharedInstance] getResultForCallToObject:self selector:@selector(fetchEntityWithId:success:failure:)];
if (response == nil)
{
failure([NSError errorWithDomain:@"entity not found" code:1 userInfo:nil]);
}
else{
success(response);
}
}
@end
그리고 마지막으로는, 테스트 자체, 당신은 호출
MyServiceTest.m
- (void)setUp
{
[super setUp];
//swizzle webservice method call to mock object call
MethodSwizzle([MyWebService class], @selector(fetchEntityWithId:success:failure:), @selector(mockFetchEntityWithId:success:failure:));
}
- (void)testWSMockedEntity
{
/* mock an entity response from the server */
[[TestConfiguration sharedInstance] setNextResult:[Entity entityWithId:1]
forCallToObject:[MyWebService sharedInstance]
selector:@selector(fetchEntityWithId:success:failure:)];
// now perform the call. You should be able to call STAssert in the blocks directly, since the success/error block should now be called completely synchronously.
}
비고 전에 설정에서 모의 방법을 스위 즐링 (swizzle), 각 시험에서 예상 답을 정의 할 : 내 예제에서, TestConfiguration 클래스/셀렉터 키 대신 개체/선택기를 사용합니다. 즉, 클래스의 모든 객체가 선택기에 대해 동일한 대답을 사용하게됩니다. 웹 서비스가 종종 싱글 톤이기 때문에 그럴 가능성이 큽니다. 하지만 객체/선택기로 클래스 대신 objet의 메모리 주소를 사용해야합니다.
각 호출에 대해 원하는 가짜 결과를 얻을 수있는 "TestConfiguration"과 같은 싱글 톤 객체를 가질 수 없습니다. 귀하의 모의 범주 내에서? –
모든 내부를 속성으로 표시 할 수 있으므로 원하는대로 클래스를 구성 할 수 있습니다. –