Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 设计一个可测试的Objective-C类_Ios_Objective C_Unit Testing_Testing_Mocking - Fatal编程技术网

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

Ios 设计一个可测试的Objective-C类,ios,objective-c,unit-testing,testing,mocking,Ios,Objective C,Unit Testing,Testing,Mocking,背景 我主要使用Java。下面是我用Objective-C编写的一些代码。我的目标是为“MyService”编写一些单元测试。仅供参考:此代码中的类名称只是一个占位符 问题 这似乎是一个合理的方法吗?我是: 给这个类一个单例方法(sharedMyService) 声明要注入的构造函数NSURLSession 合并使用realNSURLSession 我的意图是: 我想通过模拟NSURLSession 我将把NSURLSessionmock注入这个类来测试它 可能会阅读更多关于Apple文档

背景

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

问题


这似乎是一个合理的方法吗?我是:

  • 给这个类一个单例方法(
    sharedMyService
  • 声明要注入的构造函数
    NSURLSession
  • 合并使用real
    NSURLSession
我的意图是:

  • 我想通过模拟
    NSURLSession
  • 我将把
    NSURLSession
    mock注入这个类来测试它
  • 可能会阅读更多关于Apple文档或其他地方的内容,了解如何使用URL:方法模拟
    DataTask
以下是头文件:

#import <Foundation/Foundation.h>

@interface MyService : NSObject

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

+ (id)sharedMyService;

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

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

@end
“这似乎是一种合理的方法吗?”是的(尽管我们不知道您的测试旨在证明什么,也不知道您的其他代码将如何使用这个类)

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


还要考虑一下单例是否真的是适合您的方法-您是否希望能够在不同的会话中重用此类-以及工厂方法是否更好…

需要考虑以下几点:

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

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

  • 研究Objective-C模拟框架。我已经用了很多年了,几乎没有什么不能做的。与Easymock和Mockito等Java框架非常相似。但是请注意,如果您正在考虑使用Swift,那么对Swift的嘲笑几乎是不存在的。Swift根本不具备运行时功能


谢谢@josh caswell刚刚检查了我拼写错误的意思:-嘘,我甚至都不知道这是一个单词!:)
#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];
}