{"id":17301,"date":"2017-02-24T15:51:45","date_gmt":"2017-02-24T20:51:45","guid":{"rendered":"http:\/\/mjtsai.com\/blog\/?p=17301"},"modified":"2019-10-13T13:43:51","modified_gmt":"2019-10-13T17:43:51","slug":"let-your-swift-xctest-methods-throw","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2017\/02\/24\/let-your-swift-xctest-methods-throw\/","title":{"rendered":"Let Your Swift XCTest Methods Throw"},"content":{"rendered":"<p><a href=\"https:\/\/www.raizlabs.com\/dev\/2017\/02\/xctest-optional-unwrapping\/\">Brian King<\/a>:<\/p>\n<blockquote cite=\"https:\/\/www.raizlabs.com\/dev\/2017\/02\/xctest-optional-unwrapping\/\">\n<p>One place where the XCTest assertion utilities fall a bit short has been with managing Optional variables in Swift. <code>XCTAssertNotNil<\/code> doesn&rsquo;t provide any mechanism for unwrapping variables, easily leading to assertion checks like this[&#8230;]<\/p>\n<p>[&#8230;]<\/p>\n<p>A nice solution is possible, due to an often-overlooked feature of&nbsp;<code>XCTestCase<\/code>. If the test function is marked with&nbsp;<code>throws<\/code>, any thrown exception will cause the test to fail. We can use this to fail our tests using normal Swift flow control mechanisms[&#8230;]<\/p>\n<\/blockquote>\n\n<p>Unit tests are much more pleasant to read and write if you can get rid of the clutter. There are two key ways that I do this. First, I have an <code>MJTTestCase<\/code> subclass with convenience methods that wrap the <code>XCTAssert<\/code> functions. My methods have obscenely short names. For example, <code>XCTAssertTrue()<\/code> becomes <code>t()<\/code> and <code>XCTAssertEqual()<\/code> becomes <code>eq()<\/code>. Swift&rsquo;s support for unnamed parameters and overrides really helps here. These are not features that I use much in regular code, but they really come in handy with tests, where there are a small number of methods that are called many times, and I want the focus to be on the parameters rather than the methods themselves.<\/p>\n\n<p>Second, as King describes, I take advantage of the fact that test methods are now allowed to throw. This is so much better than force unwrapping. My equivalent to his <code>AssertNotNilAndUnwrap()<\/code> is called <code>unwrap()<\/code>. It avoids having to write lots of <code>guard<\/code> statements, either returning the value in the optional or failing the test. If the test fails, it throws, which is how the return type can be <code>T<\/code> instead of <code>T?<\/code>. I also have variants like <code>unwrapString()<\/code>, which also do an <code>as?<\/code> to check the type.<\/p>\n\n<p>The same technique works for checking errors. I have <code>ok()<\/code>, which takes an expression that can throw and fails the test (collecting the line number and error) if it does. If it succeeds, the return value is available for use. I also have <code>e()<\/code>, which makes sure that an <code>NSError<\/code> was thrown and returns it so that it can be inspected with further assertions. The XCTest equivalent is <code><a href=\"https:\/\/github.com\/apple\/swift-corelibs-xctest\/commit\/f98cf49c86ffcf2804cff78930c247ac1e0dafe7#diff-bb5b3151a818571b84c05803e281747fR1\">XCTAssertThrowsError()<\/a><\/code>, which wants you to pass in an <a href=\"http:\/\/makebeforebreak.com\/post\/using-xctassertthrowserror-in-your-swift-tests\/\">error handler closure<\/a>. The closure has a number of drawbacks: it causes extra boilerplate and indentation, the closure&rsquo;s body doesn&rsquo;t auto-indent properly due to an Xcode bug, and my subclass convenience methods must be accessed through <code>self<\/code>. Instead, I can simply write:<\/p>\n<pre>let error = try e(codeThatShouldThrow())\neq(error.code, NSFileNoSuchFileError)<\/pre>\n\n<p>Previously: <a href=\"http:\/\/mjtsai.com\/blog\/2016\/01\/10\/proposal-xctest-support-for-swift-error-handling\/\">Proposal: XCTest Support for Swift Error Handling<\/a>.<\/p>\n\n<p>Update (2017-03-05): By <a href=\"https:\/\/twitter.com\/olebegemann\/status\/838488070622150657\">request<\/a>, here&rsquo;s the source for my <code>unwrap()<\/code>:<\/p>\n<pre>func unwrap&lt;T&gt;(_ value: T?, file: StaticString = #file, line: UInt = #line) throws -&gt; T {\n    guard let value = value else {\n        fail(\"Unwrapped nil instead of \\(T.self)\", file: file, line: line)\n        throw ExpectedNotNilError()\n    }\n    return value\n}<\/pre>\n\n<p id=\"let-your-swift-xctest-methods-throw-update-2019-10-13\">Update (2019-10-13): Xcode 11 now includes its own <a href=\"https:\/\/developer.apple.com\/documentation\/xctest\/3380195-xctunwrap\">XCTUnwrap<\/a> (via <a href=\"https:\/\/twitter.com\/basthomas\/status\/1182576485552545799\">Bas Broek<\/a>).<\/p>","protected":false},"excerpt":{"rendered":"<p>Brian King: One place where the XCTest assertion utilities fall a bit short has been with managing Optional variables in Swift. XCTAssertNotNil doesn&rsquo;t provide any mechanism for unwrapping variables, easily leading to assertion checks like this[&#8230;] [&#8230;] A nice solution is possible, due to an often-overlooked feature of&nbsp;XCTestCase. If the test function is marked with&nbsp;throws, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2019-10-13T17:43:54Z","apple_news_api_id":"e3a0623f-a74a-4a9b-899c-6243e4a94f42","apple_news_api_modified_at":"2019-10-13T17:43:55Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/A46BiP6dKSpuJnGJD5KlPQg","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[131,31,30,71,901,268,226],"class_list":["post-17301","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-bug","tag-ios","tag-mac","tag-programming","tag-swift-programming-language","tag-testing","tag-xcode"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/17301","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=17301"}],"version-history":[{"count":7,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/17301\/revisions"}],"predecessor-version":[{"id":26857,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/17301\/revisions\/26857"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=17301"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=17301"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=17301"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}