From 1160331e566cb4ea73e9f479d1d726666d6e1df2 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Tue, 13 Nov 2018 17:55:47 -0600 Subject: [PATCH 1/5] Add the ability for test blocks to throw --- .../Testable/MTKTestable+UIViewController.swift | 4 ++-- MetovaTestKit/Testable/MTKTestable.swift | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/MetovaTestKit/Testable/MTKTestable+UIViewController.swift b/MetovaTestKit/Testable/MTKTestable+UIViewController.swift index 6752c47..fde0364 100644 --- a/MetovaTestKit/Testable/MTKTestable+UIViewController.swift +++ b/MetovaTestKit/Testable/MTKTestable+UIViewController.swift @@ -36,10 +36,10 @@ public extension MTKTestable where Self: UIViewController { - parameter testBlock: The block of tests to run. */ - static func test(_ testBlock: (Self) -> Void) { + static func test(_ testBlock: (Self) throws -> Void) rethrows { let testVC = instanceForTesting() testVC.loadView() testVC.viewDidLoad() - testBlock(testVC) + try testBlock(testVC) } } diff --git a/MetovaTestKit/Testable/MTKTestable.swift b/MetovaTestKit/Testable/MTKTestable.swift index ff7f91d..f0ea876 100644 --- a/MetovaTestKit/Testable/MTKTestable.swift +++ b/MetovaTestKit/Testable/MTKTestable.swift @@ -31,20 +31,19 @@ The MTKTestable protocol provides an alternative, functional approach to `XCTest`'s built in `setUp` & `tearDown` methods for handling unit tests. - `instanceForTesting()` should provide a new instance for each call. - `test(_:)` should effectively follow this pattern: static func test(_ testBlock: (Self) -> Void) { - - let testInstance = instanceForTesting() - + + let dependency = Dependency() + let testInstance = Self.init(injecting: dependency) + // any code that would previously live in setUp - + testBlock(testInstance) - + // any code that would previously live in tearDown - + } With these methods implemented, our test cases now look like this: @@ -74,7 +73,7 @@ public protocol MTKTestable { - parameter testBlock: A block of code containing tests to run. */ - static func test(_ testBlock: (TestableItem) -> Void) + static func test(_ testBlock: (TestableItem) throws -> Void) rethrows /** Asks the `MTKTestable` type for a new instance in order to be used for testing. This method should provide a new instance every time. From 080e51f823979c9a448bdfe1a64b5ee821d187c3 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Tue, 13 Nov 2018 18:13:14 -0600 Subject: [PATCH 2/5] Add tests to ensure failure propogation --- .../Test Data/TestableViewController.swift | 10 ++++++++++ .../TestableProtocolTests.swift | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/MetovaTestKitTests/Test Data/TestableViewController.swift b/MetovaTestKitTests/Test Data/TestableViewController.swift index 33bc42b..35947b6 100644 --- a/MetovaTestKitTests/Test Data/TestableViewController.swift +++ b/MetovaTestKitTests/Test Data/TestableViewController.swift @@ -55,6 +55,16 @@ class TestableViewController: UIViewController { testLabel.text = TestableViewController.TestLabelString testButton.setTitle(TestableViewController.TestButtonString, for: .normal) } + + func throwError() throws { + + throw ViewControllerError() + } +} + +extension TestableViewController { + + struct ViewControllerError: Error { } } // Implementing this method and marking conformance to MTKTestable protocol means we inherit the default implementation of the test(_:) method defined in the extension for the protocol for UIViewControllers. diff --git a/MetovaTestKitTests/Testable Protocol Tests/TestableProtocolTests.swift b/MetovaTestKitTests/Testable Protocol Tests/TestableProtocolTests.swift index b8acadb..04bb3bb 100644 --- a/MetovaTestKitTests/Testable Protocol Tests/TestableProtocolTests.swift +++ b/MetovaTestKitTests/Testable Protocol Tests/TestableProtocolTests.swift @@ -59,4 +59,15 @@ class TestableProtocolTests: MTKBaseTestCase { waitForExpectations(timeout: 0, handler: nil) } + + func testErrorIsThrown() { + + XCTAssertThrowsError( + + try TestableViewController.test { testVC in + + try testVC.throwError() + } + ) + } } From ac4af4b372b25c8efd12a218e6958af8e64ebfd3 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Wed, 14 Nov 2018 06:47:17 -0600 Subject: [PATCH 3/5] Fix accidental doc changes --- MetovaTestKit/Testable/MTKTestable.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/MetovaTestKit/Testable/MTKTestable.swift b/MetovaTestKit/Testable/MTKTestable.swift index f0ea876..1227aad 100644 --- a/MetovaTestKit/Testable/MTKTestable.swift +++ b/MetovaTestKit/Testable/MTKTestable.swift @@ -31,19 +31,20 @@ The MTKTestable protocol provides an alternative, functional approach to `XCTest`'s built in `setUp` & `tearDown` methods for handling unit tests. + `instanceForTesting()` should provide a new instance for each call. + `test(_:)` should effectively follow this pattern: static func test(_ testBlock: (Self) -> Void) { - - let dependency = Dependency() - let testInstance = Self.init(injecting: dependency) - + + let testInstance = instanceForTesting() + // any code that would previously live in setUp - + testBlock(testInstance) - + // any code that would previously live in tearDown - + } With these methods implemented, our test cases now look like this: From 6b9567ce3386646a314b2d38c2f8182682ef95bd Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Wed, 19 Dec 2018 12:57:50 -0600 Subject: [PATCH 4/5] Update documentation --- .../MTKTestable+UIViewController.swift | 12 ++++++----- MetovaTestKit/Testable/MTKTestable.swift | 20 +++++++++---------- README.md | 10 ++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/MetovaTestKit/Testable/MTKTestable+UIViewController.swift b/MetovaTestKit/Testable/MTKTestable+UIViewController.swift index fde0364..772eaf2 100644 --- a/MetovaTestKit/Testable/MTKTestable+UIViewController.swift +++ b/MetovaTestKit/Testable/MTKTestable+UIViewController.swift @@ -31,11 +31,13 @@ import UIKit public extension MTKTestable where Self: UIViewController { - /** - Instantiates a new testable instance of a `UIViewController` or subclass using `instanceForTesting`, executes `loadView` & `viewDidLoad` to prepare the view controller for testing, and then runs the `testBlock` with this new instance. - - - parameter testBlock: The block of tests to run. - */ + /// Instantiates a new testable instance of a `UIViewController` or + /// subclass using `instanceForTesting`, executes `loadView` & + /// `viewDidLoad` to prepare the view controller for testing, and + /// then runs the `testBlock` with this new instance. + /// + /// - Parameter testBlock: The block of tests to run. + /// - Throws: Rethrows errors thrown inside of `testBlock` static func test(_ testBlock: (Self) throws -> Void) rethrows { let testVC = instanceForTesting() testVC.loadView() diff --git a/MetovaTestKit/Testable/MTKTestable.swift b/MetovaTestKit/Testable/MTKTestable.swift index 1227aad..6adac26 100644 --- a/MetovaTestKit/Testable/MTKTestable.swift +++ b/MetovaTestKit/Testable/MTKTestable.swift @@ -69,17 +69,17 @@ public protocol MTKTestable { associatedtype TestableItem: Any - /** - Asks the `MTKTestable` type to run the given test block on an instance of the `MTKTestable` type. - - - parameter testBlock: A block of code containing tests to run. - */ + /// Asks the `MTKTestable` type to run the given test block on an + /// instance of the `MTKTestable` type. + /// + /// - Parameter testBlock: A block of code containing tests to run. + /// - Throws: Rethrows errors thrown inside of `testBlock` static func test(_ testBlock: (TestableItem) throws -> Void) rethrows - /** - Asks the `MTKTestable` type for a new instance in order to be used for testing. This method should provide a new instance every time. - - - returns: A new instance, ready for testing. - */ + /// Asks the `MTKTestable` type for a new instance in order to be + /// used for testing. This method should provide a new instance + /// every time. + /// + /// - Returns: A new instance, ready for testing. static func instanceForTesting() -> Self } diff --git a/README.md b/README.md index 890c8c7..446fca5 100755 --- a/README.md +++ b/README.md @@ -83,6 +83,16 @@ func testOutlets() { } ``` +The `test` function rethrows any errors thrown inside the `testBlock`, allowing you to leveraging `throw`ing test cases to more conveniently denote failures. + +```swift +func testLogin() throws { + try HomeViewControllerClass.test { testVC in + try testVC.login(username: "jimmythecorgi", password: "woofwoof123") + } +} +``` + ## Testing UIKit Components ### UIControl From e329918520ed5ab87effb4f192fb897a99a73010 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Wed, 19 Dec 2018 14:40:53 -0600 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0236ea6..5688701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Added convenience method for testing UICollectionViewCells - Added convenience method for testing UITableViewCells +- Added rethrowing mechanism allowing MTKTestable's `test(_:)` to propagate thrown errors. ## 2.1.0