Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for faking errors for throwing functions #4

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Prev Previous commit
Next Next commit
Add support for faking an error for throwing functions in ReturningFu…
…nctionMock (#2)
  • Loading branch information
danielr committed Jul 11, 2019
commit 7ad67b87bb718538fd2b18b00f5315fc3cc30d66
2 changes: 1 addition & 1 deletion Mokka/Sources/FunctionMock/FunctionMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class FunctionMock<Args> {
public var argument: Args? { return arguments } // syntactic alternative for single-arg methods

private var stubBlock: ((Args) -> Void)?
private var error: Error?
internal var error: Error?

/// Creates a new instance of a function mock with the specified name.
///
Expand Down
41 changes: 32 additions & 9 deletions Mokka/Sources/FunctionMock/ReturningFunctionMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,28 @@ public class ReturningFunctionMock<Args, ReturnValue>: FunctionMock<Args> {
///
/// - parameters:
/// - args: The arguments that the mocked function has been called with.
/// - returns: The return value configured via `returns(...)`.
public func recordCallAndReturn(_ args: Args) -> ReturnValue {
recordCall(args)

// stub return value
guard let stub = stubs.first(where: { $0.shouldHandle(args) }) else {
if let returnValue = defaultReturnValue {
return returnValue
}
preconditionFailure("No return value for \(name ?? "function")")
return getReturnValue(args: args)
}

/// Record a call of the mocked function and potentially throw an error, if configured.
///
/// - parameters:
/// - args: The arguments that the mocked function has been called with.
/// - returns: The return value configured via `returns(...)`.
/// - throws: The error that has been configured via `throws(_:)`, if any.
public func recordCallAndReturnOrThrow(_ args: Args) throws -> ReturnValue {
recordCall(args)

if let error = error {
throw error
} else {
return getReturnValue(args: args)
}

return stub.handle(args)
}


// MARK: - Stubbing

Expand Down Expand Up @@ -113,6 +122,20 @@ public class ReturningFunctionMock<Args, ReturnValue>: FunctionMock<Args> {
stubs.append(stub)
}

// MARK: - Private

/// Get the stubbed return value for the specified arguments.
private func getReturnValue(args: Args) -> ReturnValue {
guard let stub = stubs.first(where: { $0.shouldHandle(args) }) else {
if let returnValue = defaultReturnValue {
return returnValue
}
preconditionFailure("No return value for \(name ?? "function")")
}

return stub.handle(args)
}

// MARK: - FunctionStub

/// Used internally to represent a static or dynamic stubbed return
Expand Down
41 changes: 41 additions & 0 deletions Mokka/Tests/FunctionMock/ReturningFunctionMockTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,47 @@ class ReturningFunctionMockTests: XCTestCase {
XCTAssertEqual(result, 42)
}

// MARK: Throwing

func testDoesNotThrowErrorIfNotExplicitlyConfigured() {
sut.returns(42)
XCTAssertNoThrow(try sut.recordCallAndReturnOrThrow("foo"))
}

func testThrowsErrorAfterSettingError() {
sut.throws(TestError.errorOne)
XCTAssertThrowsError(try sut.recordCallAndReturnOrThrow("foo")) { error in
XCTAssert(error is TestError, "Unexpected error type thrown")
XCTAssertEqual(error as! TestError, TestError.errorOne)
}
}

func testRecordCallAndReturnOrThrowRecordsCallsWhenNotThrowing() {
sut.returns(42)
XCTAssertNoThrow(try sut.recordCallAndReturnOrThrow("foo"))
XCTAssertNoThrow(try sut.recordCallAndReturnOrThrow("bar"))
XCTAssertEqual(sut.callCount, 2)
}

func testRecordCallAndReturnOrThrowCapturesArgumentsWhenNotThrowing() {
sut.returns(42)
XCTAssertNoThrow(try sut.recordCallAndReturnOrThrow("foo"))
XCTAssertEqual(sut.argument, "foo")
}

func testRecordCallAndReturnOrThrowRecordsCallsWhenThrowing() {
sut.throws(TestError.errorOne)
XCTAssertThrowsError(try sut.recordCallAndReturnOrThrow("foo"))
XCTAssertThrowsError(try sut.recordCallAndReturnOrThrow("bar"))
XCTAssertEqual(sut.callCount, 2)
}

func testRecordCallAndReturnOrThrowCapturesArgumentsWhenThrowing() {
sut.throws(TestError.errorOne)
XCTAssertThrowsError(try sut.recordCallAndReturnOrThrow("foo"))
XCTAssertEqual(sut.argument, "foo")
}

// MARK: Reset

func testCallCountIsZeroAfterReset() {
Expand Down