LoginSignup
3
3

More than 5 years have passed since last update.

iOSのUnitTest用モックサーバーをYAMLとJSONから作る

Last updated at Posted at 2015-08-06

ニフティクラウド mobile backend(mBaaS)のSDKテスト用に、
YAMLとJSONファイルでモックサーバーが定義できれば、
AndroidでもiOSでも使いまわせるという作戦です。

前回のAndroidのUnitTest用モックサーバーをYAMLとJSONから作るのをiOSにも展開しました

Androidのほうはクエリストリングとリクエストボディで
レスポンスを切り替える改修もしているので別途どこかで共有します

YAMLを扱うライブラリ

target :YOUR_TARGET_NAME do
  pod 'Specta'
  pod 'Expecta'
  pod 'OHHTTPStubs'
  pod 'YAML-Framework'
end

テストコード

ポイント

NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"mbaas" ofType:@"yml"];
NSData *ymlData = [NSData dataWithContentsOfFile:path];

YAMLとJSONファイル

  • resource/yamlグループとresource/jsonグループをXcodeでつくりましたが、あんまり関係ないです
    • Build PhasesのCopy Bundle Resourcesに追加されていればOKだと思います

YAMLファイル

---
  request:
    url: /2013-09-01/classes/TestClass/testObjectId
    method: GET
  response:
    status: 201
    file: valid_get_request.json

JSONファイル

{"objectId":"testObjectId","createDate":"2015-08-05T00:00:00.000Z","updateDate":"2015-08-05T00:00:00.000Z","acl":{"*":{"read":true, "write":true}}}

テストコード全文

#import <Specta/Specta.h>
#import <Expecta/Expecta.h>
#import <OHHTTPStubs/OHHTTPStubs.h>
#import <YAML-Framework/YAMLSerialization.h>

SpecBegin(StubTest)

beforeAll(^{

    //Yaml file reading
    NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"mbaas" ofType:@"yml"];
    NSData *ymlData = [NSData dataWithContentsOfFile:path];
    NSError *error = nil;
    NSMutableArray *yaml = [YAMLSerialization objectsWithYAMLData:ymlData
                                                          options: kYAMLReadOptionStringScalars
                                                            error: &error];

    //set default response
    NSDictionary *responseDic = @{@"code":@"E404001",
                                  @"error":@"Not found request"};
    NSData *jsonResponse = [NSJSONSerialization dataWithJSONObject:responseDic options:0 error:nil];

    //CreateStub
    [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
        for (NSDictionary *stub in yaml){
            NSDictionary *stubRequest = [stub objectForKey:@"request"];
            if (![[stubRequest objectForKey:@"url"] isEqualToString:request.URL.path]){
                continue;
            }
            if (![[stubRequest objectForKey:@"method"] isEqualToString:request.HTTPMethod]){
                continue;
            }
            return YES;
        }
        return NO;
    } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
        for (NSDictionary *stub in yaml){
            NSDictionary *stubRequest = [stub objectForKey:@"request"];
            if (![[stubRequest objectForKey:@"url"] isEqualToString:request.URL.path]){
                continue;
            }
            if (![[stubRequest objectForKey:@"method"] isEqualToString:request.HTTPMethod]){
                continue;
            }
            NSString *jsonFileName = [[stub objectForKey:@"response"] objectForKey:@"file"];
            NSArray *fileNameArray = [jsonFileName componentsSeparatedByString:@"."];
            NSString *jsonPath = [[NSBundle bundleForClass:[self class]] pathForResource:fileNameArray[0]
                                                                                  ofType:fileNameArray[1]];

            return [OHHTTPStubsResponse responseWithData:[NSData dataWithContentsOfFile:jsonPath]
                                              statusCode:[[[stub objectForKey:@"response"] objectForKey:@"status"] intValue]
                                                 headers:@{@"Content-Type":@"application/json"}];;
        }
        return [OHHTTPStubsResponse responseWithData:jsonResponse
                                          statusCode:404
                                             headers:@{@"Content-Type":@"application/json"}];
    }];
});

describe(@"OHHTTPStubs", ^{
    it(@"should return stub response", ^{
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/2013-09-01/classes/TestClass/testObjectId"]];
        NSHTTPURLResponse *response = nil;
        NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
        NSDictionary *responseDic = [NSJSONSerialization JSONObjectWithData:responseData
                                               options:NSJSONReadingAllowFragments
                                                 error:nil];
        expect([responseDic objectForKey:@"objectId"]).to.equal(@"testObjectId");
    });
});

afterAll(^{
    [OHHTTPStubs removeAllStubs];
});

SpecEnd

さいごに

  • デフォルトのレスポンスを作成するのであれば、リクエストをチェックする部分はすぐtrueを返してもいい気がしています。YAMLファイルの中身を2回チェックしているので。。。
//このfor文が2回実装されている。。。
for (NSDictionary *stub in yaml){

}
  • (まだ)URLのパスとリクエストメソッドしかチェックしていません
  • AndroidもiOSもいつかライブラリにしてしまいたいです
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3