Last active
March 22, 2018 06:43
-
-
Save matsuda/e77c93dc0aeb093bcd8882af1eec4433 to your computer and use it in GitHub Desktop.
XCTestにおけるスタブ(仮)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// テストターゲット=`SampleAppTest` | |
// ホストアプリ=`SampleApp` | |
import Foundation | |
import Alamofire | |
struct APIStub { | |
let statusCode: Int | |
let result: Result<Data>? | |
var data: Data? { | |
switch result { | |
case .some(.success(let data)): | |
return data | |
default: | |
return nil | |
} | |
} | |
var error: Error? { | |
switch result { | |
case .some(.failure(let error)): | |
return error | |
default: | |
return nil | |
} | |
} | |
} | |
class APIStubProtocol: URLProtocol { | |
private static var stub: APIStub? | |
override class func canInit(with request: URLRequest) -> Bool { | |
if stub == nil { return false } | |
return true | |
} | |
override class func canonicalRequest(for request: URLRequest) -> URLRequest { | |
return request | |
} | |
override func startLoading() { | |
defer { | |
APIStubProtocol.resetStub() | |
} | |
if let stub = APIStubProtocol.stub, let data = stub.data, (200..<400).contains(stub.statusCode) { | |
let response = HTTPURLResponse(url: request.url!, statusCode: stub.statusCode, httpVersion: "HTTP/1.1", headerFields: [:]) | |
client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) | |
client?.urlProtocol(self, didLoad: data) | |
client?.urlProtocolDidFinishLoading(self) | |
return | |
} | |
var statusCode: Int = 400 | |
var error: Error = NSError(domain: "SampleAppTest", code: 10001, userInfo: nil) | |
if let stub = APIStubProtocol.stub { | |
statusCode = stub.statusCode | |
if let e = stub.error { | |
error = e | |
} | |
} | |
let response = HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "HTTP/1.1", headerFields: [:]) | |
client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) | |
client?.urlProtocol(self, didFailWithError: error) | |
} | |
override func stopLoading() { | |
APIStubProtocol.resetStub() | |
} | |
class func addStub(_ stub: APIStub) { | |
self.stub = stub | |
} | |
class func resetStub() { | |
self.stub = nil | |
} | |
} | |
extension URLSessionConfiguration { | |
@objc class func swizzlingAPIStub() { | |
let defaultConfig = class_getClassMethod(URLSessionConfiguration.self, #selector(getter:URLSessionConfiguration.default)) | |
let stubbedConfig = class_getClassMethod(URLSessionConfiguration.self, #selector(URLSessionConfiguration.stubbedDefaultConfiguration)) | |
method_exchangeImplementations(defaultConfig!, stubbedConfig!) | |
} | |
@objc class func stubbedDefaultConfiguration() -> URLSessionConfiguration { | |
let config = stubbedDefaultConfiguration() | |
config.protocolClasses = [APIStubProtocol.self] as [AnyClass] + config.protocolClasses! | |
return config | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// テストターゲット=`SampleAppTest` | |
// ホストアプリ=`SampleApp` | |
import XCTest | |
@testable import SampleApp | |
class ArticleAPITests: BaseTestCase { | |
override func setUp() { | |
super.setUp() | |
} | |
override func tearDown() { | |
super.tearDown() | |
APIStubProtocol.resetStub() | |
} | |
func testStub() { | |
// Given | |
let expectation = XCTestExpectation(description: "request should succeed") | |
APIStubProtocol.addStub(APIStub(statusCode: 200, result: stubResult(forResource: "articles", withExtension: "json"))) | |
// When | |
ArticleAPI().get { (result) in | |
// Then | |
XCTAssertNotNil(result) | |
XCTAssert(result?.isSuccess == true, "response should be success") | |
XCTAssertNil(result?.errorCode) | |
XCTAssertNotNil(result?.data) | |
XCTAssertEqual(result?.data?.first?.id, 123) | |
expectation.fulfill() | |
} | |
wait(for: [expectation], timeout: 1.0) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// テストターゲット=`SampleAppTest` | |
// ホストアプリ=`SampleApp` | |
import XCTest | |
import Alamofire | |
class BaseTestCase: XCTestCase { | |
override func setUp() { | |
super.setUp() | |
// Put setup code here. This method is called before the invocation of each test method in the class. | |
} | |
func stubURL(forResource fileName: String, withExtension ext: String = "json") -> URL { | |
return Bundle(for: BaseTestCase.self).url(forResource: fileName, withExtension: ext)! | |
} | |
func stubData(forResource fileName: String, withExtension ext: String = "json") -> Data { | |
return try! Data(contentsOf: stubURL(forResource: fileName, withExtension: ext)) | |
} | |
func stubResult(forResource fileName: String, withExtension ext: String = "json") -> Result<Data> { | |
return Result<Data>.success(stubData(forResource: fileName, withExtension: ext)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// テストターゲット=`SampleAppTest` | |
// ホストアプリ=`SampleApp` | |
#import <Foundation/Foundation.h> | |
#import <SampleAppTest-Swift.h> | |
@interface StubLoader: NSObject | |
@end | |
@implementation StubLoader | |
+ (void)load { | |
[NSURLSessionConfiguration swizzlingAPIStub]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment