カッコウで「濡れた」オブジェクト


この投稿は、Godfrey Nolanによる記事「 Mocking in Swift with Cuckoo」に基づいています


モバイル開発者による彼の「サービス」の義務のため、私の前にタスクが現れました:単体テストのためのMokovの作成と使用に対処することです。 私の同僚はカッコウの図書館を勧めました。 私は彼女に対処し始めました、それはそれから来たものです。


ドキュメント


githubのドキュメントを読んだ後、残念ながら、プロジェクトでCuckooを「取得」できませんでした。 このフレームワークはCocoaPodsを介してインストールされましたが、Runスクリプトに問題がありました。提案された例では、テストフォルダーにGeneratedMocks.swiftファイルが作成されず、 。


そのため、すべての段階を一緒に進め、いくつかのニュアンスに対処します。


テストプロジェクト


当然、Cuckooをプラグインしてテストを作成するプロジェクトが必要です。 Xcodeを開き、新しいシングルビューアプリケーションを作成します。言語はSwiftです。必ず、 Include Unit TestsチェックボックスをUrlWithCuckoo 、プロジェクト名はUrlWithCuckooです。


新しいSwiftファイルをプロジェクトに追加し、 UrlSession.swiftという名前をUrlSession.swiftます。 完全なコードは次のとおりです。


 import Foundation class UrlSession { var url:URL? var session:URLSession? var apiUrl:String? func getSourceUrl(apiUrl:String) -> URL { url = URL(string:apiUrl) return url! } func callApi(url:URL) -> String { session = URLSession() var outputdata:String = "" let task = session?.dataTask(with: url as URL) { (data, _, _) -> Void in if let data = data { outputdata = String(data: data, encoding: String.Encoding.utf8)! print(outputdata) } } task?.resume() return outputdata } } 

ご覧のとおり、これは3つのプロパティと2つのメソッドを持つ単純なクラスです。 このクラスのためにモックを作成します。


カッコウを接続する


私は仕事でCocoaPodsを使用しているため、Cuckooに接続するには、このタイプのディレクトリをPodfileプロジェクトディレクトリに追加します。


 platform :ios, '9.0' use_frameworks! target 'UrlWithCuckooTests' do pod 'Cuckoo' end 

当然、プロジェクトディレクトリからターミナルでpod installを実行する必要があります。インストールが完了しUrlWithCuckoo.xcworkspace 、XcodeでUrlWithCuckoo.xcworkspaceを開きます。


次のステップは、「ターゲット」テストのビルドフェーズに実行スクリプトを追加することです(「+」をクリックして「新規実行スクリプトフェーズ」を選択する必要があります)。



完全なスクリプトは次のとおりです。


 # Define output file; change "${PROJECT_NAME}Tests" to your test's root source folder, if it's not the default name OUTPUT_FILE="./${PROJECT_NAME}Tests/GeneratedMocks.swift" echo "Generated Mocks File = ${OUTPUT_FILE}" # Define input directory; change "${PROJECT_NAME}" to your project's root source folder, if it's not the default name INPUT_DIR="./${PROJECT_NAME}" echo "Mocks Input Directory = ${INPUT_DIR}" # Generate mock files; include as many input files as you'd like to create mocks for ${PODS_ROOT}/Cuckoo/run generate --testable "${PROJECT_NAME}" \ --output "${OUTPUT_FILE}" \ "${INPUT_DIR}/UrlSession.swift" 

ご覧のとおり、スクリプトのコメントには、 ${PROJECT_NAME}Tests${PROJECT_NAME}Testsを置き換える必要があることが記載されていますが、この例では必要ありません。


モックを生成(s)


次に、このスクリプトが動作し、テストディレクトリにGeneratedMocks.swiftファイルを作成する必要があります。プロジェクト( Cmd+B )をビルドするだけでは不十分です。 Build Shift+Cmd+U > Testing( Shift+Cmd+U )を実行する必要があります:



GeneratedMocks.swiftファイルがUrlWithCuckooTestsディレクトリに表示されることGeneratedMocks.swift確認します。 その(ファイル)もプロジェクト自体に追加する必要があります:FinderからUrlWithCuckooTests XcodeにドラッグするだけUrlWithCuckooTests



モキの準備ができました。いくつかのニュアンスについて話しましょう。


1.複雑なファイル構造


プロジェクトに通常のファイル構造があり、ファイルがルートディレクトリだけでなくサブフォルダに配置されている場合は、スクリプトを調整する必要があります。


プロジェクトでMVPを使用し、 MainModuleモジュールのMainModule Controllerのモックが必要であるとMainModuleます(もちろん、プロジェクトでは/Modules/MainModule/MainModuleViewController.swift )。 この場合、スクリプトの最後の行を"${INPUT_DIR}/UrlSession.swift"例から"${INPUT_DIR}/UrlSession.swift"に変更する必要があります。


また、 GeneratedMocks.swiftファイルをテストのルートディレクトリだけでなく、たとえばModulesサブフォルダーにもOUTPUT_FILE="./${PROJECT_NAME}Tests/GeneratedMocks.swift"たい場合は、スクリプトの次の行を修正する必要がありますOUTPUT_FILE="./${PROJECT_NAME}Tests/GeneratedMocks.swift"


2. Mokiのいくつかのクラスが必要


いくつかのクラスのMokiが必要になる可能性は非常に高いです(予想される確率は99.9%です)。 スクリプトの最後にMokiを作成する必要のあるファイルをリストし、バックスラッシュで分割するだけで作成できます。


 "${INPUT_DIR}/UrlSession.swift" \ "${INPUT_DIR}/Modules/MainModule/MainModuleViewController.swift" \ "${INPUT_DIR}/MyAwesomeObject.swift" 

3.型注釈


Mokiを作成するクラスでは、すべてのプロパティに型注釈が必要です。 このようなものがある場合:


 var someBoolVariable = false 

その後、Mokを生成すると、エラーが発生します。



ファイルGeneratedMocks.swift__UnknownTypeが表示され__UnknownType



残念ながら、Cuckooはデフォルト値でタイプを決定できません。この場合、プロパティのタイプを明示的に指定する必要があります。


 var someBoolVariable: Bool = false 

テストを書く


次に、モックを使用して簡単なテストを作成しましょう。 UrlWithCuckooTests.swiftファイルを開き、デフォルトで作成される2つのメソッドfunc testExample()およびfunc testPerformanceExample()ます。 それらは必要ありません。 そしてもちろん、忘れないでください:


 import Cuckoo 

1.プロパティ


最初に、プロパティのテストを記述します。 新しいメソッドを作成します。


 func testVariables() { } 

その中のMockといくつかの追加の定数を初期化します。


 let mock = MockUrlSession() let urlStr = "http://habrahabr.ru" let url = URL(string:urlStr)! 

次に、プロパティのスタブを記述する必要があります。


 // Arrange stub(mock) { (mock) in when(mock.url).get.thenReturn(url) } stub(mock) { (mock) in when(mock.session).get.thenReturn(URLSession()) } stub(mock) { (mock) in when(mock.apiUrl).get.thenReturn(urlStr) } 

スタブは、返される結果を置き換えるようなものです。 大ざっぱに言えば、我々が真岡に頼ったときに真岡の財産を返すものを説明します。 ご覧のthenReturnthenReturnを使用していますが、 thenReturnを使用できます。 これは、値を返すだけでなく、追加のアクションを実行する機会を提供します。 たとえば、最初のスタブは次のように記述できます。


 // Arrange stub(mock) { (mock) in when(mock.url).get.then { (_) -> URL? in // some actions here return url } } 

そして、実際には、(値とnil )チェックします:


 // Act and Assert XCTAssertEqual(mock.url?.absoluteString, urlStr) XCTAssertNotNil(mock.session) XCTAssertEqual(mock.apiUrl, urlStr) XCTAssertNotNil(verify(mock).url) XCTAssertNotNil(verify(mock).session) XCTAssertNotNil(verify(mock).apiUrl) 

2.メソッド


次に、Mokaのメソッドの呼び出しをテストします。 2つのテストメソッドを作成してみましょう。


 func testGetSourceUrl() { } func testCallApi() { } 

どちらの方法でも、モック定数と補助定数を初期化します。


 let mock = MockUrlSession() let urlStr = "http://habrahabr.ru" let url = URL(string:urlStr)! 

また、 testCallApi()メソッドで、呼び出しカウンターを追加します。


 var callApiCount = 0 

さらに両方のメソッドで、スタブを作成します。


testGetSourceUrl()


 // Arrange stub(mock) { (mock) in mock.getSourceUrl(apiUrl: urlStr).thenReturn(url) } 

testCallApi()


 // Arrange stub(mock) { mock in mock.callApi(url: equal(to: url, equalWhen: { $0 == $1 })).then { (_) -> String in callApiCount += 1 return "{'firstName': 'John','lastName': 'Smith'}" } } 

最初の方法を確認します。


 // Act and Assert XCTAssertEqual(mock.getSourceUrl(apiUrl: urlStr), url) XCTAssertNotEqual(mock.getSourceUrl(apiUrl: urlStr), URL(string:"http://google.com")) verify(mock, times(2)).getSourceUrl(apiUrl: urlStr) 

(最後の行では、メソッドが2回呼び出されたことを確認します)


そして2つ目:


 // Act and Assert XCTAssertEqual(mock.callApi(url: url),"{'firstName': 'John','lastName': 'Smith'}") XCTAssertNotEqual(mock.callApi(url: url), "Something else") verify(mock, times(2)).callApi(url: equal(to: url, equalWhen: { $0 == $1 })) XCTAssertEqual(callApiCount, 2) 

(ここで、2つの方法で呼び出しの数も確認します:以前に発表したverifycallApiCount呼び出しcallApiCountを使用します)


テストを実行する


テスト用のプロジェクト( Cmd+U )を開始すると、次の図が表示されます。



すべてがうまくいきます。 :)


そして最後に


最終結果へのリンク: https : //github.com/ssuhanov/UrlWithCuckoo


ご清聴ありがとうございました。



Source: https://habr.com/ru/post/J322572/


All Articles