设计一个可测试的Objective-C类

时间:2016-06-19 08:39:38

标签: ios objective-c unit-testing testing mocking

背景

我主要使用Java。这是我在Objective-C中编写的一些代码。我的目标是为“MyService”编写一些单元测试。仅供参考:此代码中类的名称只是占位符。

问题

这看起来像是一种合理的方法吗?我是:

  • 为此课程提供单身方法(sharedMyService
  • 声明构造函数以注入NSURLSession
  • 合并使用真实NSURLSession
  • 的默认构造函数

我的意图是:

  • 我想通过模拟NSURLSession
  • 来测试此代码
  • 我会将NSURLSession模拟注入此类来测试它
  • 可能会在Apple文档或其他地方详细了解如何模拟dataTaskWithURL:方法。

这是头文件:

#import <Foundation/Foundation.h>

@interface MyService : NSObject

@property(nonatomic, strong, readwrite) NSURLSession *session;

+ (id)sharedMyService;

- (instancetype)initWithURLSession:(NSURLSession *)session;

- (void)fetchData:(NSString*)location;

@end

实施......

#import "MyService.h"

@implementation MyService

static NSString *const targetUri = @"http://something.com/%@";

+ (instancetype)sharedMyService {
    static MyService *service = nil;
    @synchronized (self) {
        if (service == nil) {
            service = [[self alloc] init];
        }
    }
    return service;
}

- (instancetype)initWithURLSession:(NSURLSession *)session {
    self = [super init];
    if (self) {
        self.session = session;
    }
    return self;
}

- (instancetype)init {
    return [self initWithURLSession:[NSURLSession sharedSession]];
}

- (NSURLSession *)getSession {
    return self.session;
}

- (void)fetchData:(NSString*)location {
    NSURL *targetUrl = [NSURL URLWithString:[NSString stringWithFormat:targetUri, location]];
    NSURLSession *urlSession = [self getSession];
    NSURLSessionTask *sessionTask = [urlSession dataTaskWithURL:targetUrl completionHandler: ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"Request succeeded.");
    }];
    [sessionTask resume];
}

2 个答案:

答案 0 :(得分:2)

要考虑的几件事情:

  • 在我看来,设计iOS代码(Objective-C或Swift)与使用Java设计代码没有什么不同。同样的原则也适用,你也可以这样做。

  • 尽可能避免单身人士。例如,您仍然可以在类上拥有一个访问器来返回您的服务,但也有一个方法可以清除,重置或注入新实例。纯单一模式是测试后端的一个难点,单身人士经常在许多iOS项目中过度使用。在我的代码中,即使我可以编写单例代码,我通常也可以将它们设置为可设置(即使只是来自单元测试源代码中的类别)。

  • 查看OCMock Objective-C模拟框架。我已经使用了很多年,而且它几乎无法做到。与Easymock和Mockito等Java框架非常相似。请注意,如果您正在考虑使用Swift,那么Swift的模拟几乎不存在。 Swift根本没有运行时功能。

答案 1 :(得分:0)

&#34;这看起来像是一种合理的做法吗?&#34;是(虽然我们不知道您的测试旨在证明什么,或者您的其他代码将如何使用此类)。

显然还有其他选项,例如使用子类来实现额外的可测试性。这样做的好处是,您不会通过公开将该类声明为单例和可实例化的类来混淆用户。

还要考虑一个单身人士是否真的适合你 - 你是否希望能够在不同的会话中重复使用这个课程 - 以及工厂方法是否会更好......