diff --git a/FTTestingKit.podspec b/FTTestingKit.podspec index fa18db7..d5d29ed 100644 --- a/FTTestingKit.podspec +++ b/FTTestingKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "FTTestingKit" - s.version = "0.2.0" + s.version = "0.3.0" s.summary = "Mockup and asynchronous testing protocols and extensions." s.description = <<-DESC Testing helpers for easier testing mockups and asynchronous testing. diff --git a/README.md b/README.md index 1941c7b..4cd5975 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,92 @@ # FTTestingKit -A description of this package. +![Cocoapods](https://img.shields.io/cocoapods/v/FTTestingKit) +![Cocoapods platforms](https://img.shields.io/cocoapods/p/FTTestingKit) +![Cocoapods](https://img.shields.io/cocoapods/l/FTTestingKit) +![Bitrise](https://img.shields.io/bitrise/f8e8740dfdd3c6a2?token=_ejKL14TVCB_KLWT4-wDxw) + +A set of helpers for simple creation of mockups, random values and testing of asynchronous code. + +## Installation + +When using Swift package manager add this line +to your dependencies or install using Xcode 11 or newer: + +```swift +.package(url: "https://github.com/thefuntasty/FTTestingKit.git", from: "0.3.0") +``` + +When using CocoaPods add following line to your `Podfile`: + +```ruby +pod 'FTTestingKit', '~> 0.3' +``` + +When using `PromiseKit` you can use either `FTTestingKitPromiseKit` +target for testing promises or add subspec to your `Podfile`: + +```ruby +pod 'FTTestingKit', '~> 0.3', subspecs: ['PromiseKit'] +``` + +## Features + +Main features of this library are generating mockups, +random values, arrays and asynchronous testing. + +### Mockups + +For simple repeated execution the library offers Ruby-like extension on `Int` type. This is helpful in measurement tests. + +```swift +10.times { + doSomething() +} +10.times(doSomething) +``` + +This extension can create arrays too: + +```swift +10.times { + Int.random() +} +10.times(String.random) +``` + +The framework extends some basic types (`Date`, `String`) +with random generation similar to `Int`. +All these types conform to `Mockup` protocol +which formally describes this functionality. + +```swift +Date.random() +String.random() +Int.random(count: 10) +``` + +### Expectations + +The framework extends `XCTestCase` with simple methods to call transactional asynchronous test like this: + +```swift +expect(within: 0.5) { reply in + DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { + reply(.success) + } +} +``` + +Extension for `PromiseKit` builds on this and offers testing promises using so-called belief in promise method: + +```swift +believe(for: 0.5, in: someFunctionReturningPromise()) +``` + +## Author + +Matěj Kašpar Jirásek, + +## License + +FTTestingKit is available under the MIT license. See the [LICENSE file](LICENSE) for more info. diff --git a/Sources/FTTestingKit/Int+Times.swift b/Sources/FTTestingKit/Int+Times.swift index b6c5cbf..d5cb8da 100644 --- a/Sources/FTTestingKit/Int+Times.swift +++ b/Sources/FTTestingKit/Int+Times.swift @@ -1,11 +1,18 @@ -public extension Int { - func times(execute: () -> Void) { +extension Int { + /// Executes supplied closure n-times. + /// Handy for time measurement tests. + /// - Parameter execute: Closure executed n-times. + public func times(execute: () -> Void) { for _ in 0..(execute: () -> T) -> [T] { + /// Creates array of items by executing supplied + /// closure n-times. Handy for generating + /// arrays of random values. + /// - Parameter execute: Closure returning some item n-times. + public func times(execute: () -> T) -> [T] { return (0.. Self + /// Generates array of randomly generated mockups. + /// - Parameter count: Number of generated items. + static func random(count: Int) -> [Self] } public extension Mockup { diff --git a/Sources/FTTestingKit/Result+Void.swift b/Sources/FTTestingKit/Result+Void.swift index 990e5a0..a58a509 100644 --- a/Sources/FTTestingKit/Result+Void.swift +++ b/Sources/FTTestingKit/Result+Void.swift @@ -1,4 +1,5 @@ public extension Result where Success == Void { + /// Convenience case for success results with void values. static var success: Result { return .success(()) } diff --git a/Sources/FTTestingKit/String+Mockup.swift b/Sources/FTTestingKit/String+Mockup.swift index 9e6c92e..b11aad5 100644 --- a/Sources/FTTestingKit/String+Mockup.swift +++ b/Sources/FTTestingKit/String+Mockup.swift @@ -6,6 +6,9 @@ extension String: Mockup { return random(length: 15, characters: mockupCharacters) } + /// Generates random string of required length from supplied characters. + /// - Parameter length: Length of the generated string in characters. + /// - Parameter characters: Array of characters used to generate the random string. public static func random( length: Int, characters: [Character] diff --git a/Sources/FTTestingKit/XCTest+Expect.swift b/Sources/FTTestingKit/XCTest+Expect.swift index bf65cb9..db6fc07 100644 --- a/Sources/FTTestingKit/XCTest+Expect.swift +++ b/Sources/FTTestingKit/XCTest+Expect.swift @@ -1,6 +1,12 @@ import XCTest public extension XCTestCase { + /// Executes new asynchronous test using expectation and encapsulates the operation + /// into transaction inside a closure. + /// - Parameter seconds: Seconds until the expectations will time-out. + /// - Parameter reply: Closure for encapsulating asynchronous tests into transactions, + /// the parameter of the clousre is callback for returning the result + /// of the asynchronous operation. func expect( within seconds: TimeInterval, reply: @escaping (@escaping (Result) -> Void) -> Void diff --git a/Sources/FTTestingKitPromiseKit/XCTest+Believe.swift b/Sources/FTTestingKitPromiseKit/XCTest+Believe.swift index c9ca1c5..f6f5a66 100644 --- a/Sources/FTTestingKitPromiseKit/XCTest+Believe.swift +++ b/Sources/FTTestingKitPromiseKit/XCTest+Believe.swift @@ -5,6 +5,11 @@ import FTTestingKit #endif public extension XCTestCase { + /// Executes new asynchronous test using expectation and encapsulates the operation + /// into a closure returning promise. + /// - Parameter timeInterval: Number of seconds until the test will time-out. + /// - Parameter promise: Operation encapsulated inside of promise which will be + /// tested for time-out and successful result. func believe(for timeInterval: TimeInterval, in promise: @escaping @autoclosure () throws -> Promise) { expect(within: timeInterval) { reply in firstly { try promise() }.asVoid().recover { error in @@ -15,6 +20,11 @@ public extension XCTestCase { } } + /// Executes new asynchronous test using expectation and encapsulates the operation + /// into a closure returning guarantee. + /// - Parameter timeInterval: Number of seconds until the test will time-out. + /// - Parameter promise: Operation encapsulated inside of guarantee which will be + /// tested for time-out and successful result. func believe(for timeInterval: TimeInterval, in guarantee: @escaping @autoclosure () -> Guarantee) { expect(within: timeInterval) { reply in guarantee().asVoid().done { diff --git a/Tests/FTTestingKitPromiseKitTests/BelieveTests.swift b/Tests/FTTestingKitPromiseKitTests/BelieveTests.swift index 475de29..56c8200 100644 --- a/Tests/FTTestingKitPromiseKitTests/BelieveTests.swift +++ b/Tests/FTTestingKitPromiseKitTests/BelieveTests.swift @@ -4,11 +4,11 @@ import FTTestingKitPromiseKit final class BelieveTests: XCTestCase { func testInstantPromise() { - believe(for: 0.1, in: Promise()) + believe(for: 0.5, in: Promise()) } func testDelayedPromise() { - believe(for: 0.1, in: after(seconds: 0.05)) + believe(for: 0.5, in: after(seconds: 0.05)) } static var allTests = [ diff --git a/Tests/FTTestingKitTests/ExpectationTests.swift b/Tests/FTTestingKitTests/ExpectationTests.swift index 4abb761..4f4fffd 100644 --- a/Tests/FTTestingKitTests/ExpectationTests.swift +++ b/Tests/FTTestingKitTests/ExpectationTests.swift @@ -3,13 +3,13 @@ import FTTestingKit final class ExpectationTests: XCTestCase { func testInstantExpectation() { - expect(within: 0.1) { reply in + expect(within: 0.5) { reply in reply(.success) } } func testAsyncExpectation() { - expect(within: 0.1) { reply in + expect(within: 0.5) { reply in DispatchQueue.main.async { reply(.success) } @@ -17,7 +17,7 @@ final class ExpectationTests: XCTestCase { } func testDelayedExpectation() { - expect(within: 0.1) { reply in + expect(within: 0.5) { reply in DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { reply(.success) }