Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# DevTesting Changelog


## 1.1.0: September 17, 2025

Adds two initializers to `ThrowingStub`: `init(defaultReturnValue:resultQueue:)` and
`init(defaultError:resultQueue:)`. These initializers enable cleaner call sites, as in the following
example:

// Before
mock.doSomethingSuccessfullyStub = ThrowingStub(defaultResult: .success(value))
mock.doSomethingUnsuccessfullyStub = ThrowingStub(defaultResult: .failure(error))

// After
mock.doSomethingSuccessfullyStub = ThrowingStub(defaultReturnValue: value)
mock.doSomethingUnsuccessfullyStub = ThrowingStub(defaultError: error)


## 1.0.0: September 1, 2025

This is the first release of DevTesting. The initial feature set includes
Expand Down
38 changes: 27 additions & 11 deletions Sources/DevTesting/Stubbing/Stub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,32 @@ public final class ThrowingStub<Arguments, ReturnType, ErrorType> where ErrorTyp


extension ThrowingStub {
/// Creates a new throwing stub with a default success result.
///
/// - Parameters:
/// - defaultReturnValue: The successful return value of the stub when the result queue is empty.
/// - resultQueue: A queue of call results to use. If empty, `defaultResult` is used.
public convenience init(
defaultReturnValue: ReturnType,
resultQueue: [Result<ReturnType, ErrorType>] = []
) {
self.init(defaultResult: .success(defaultReturnValue), resultQueue: resultQueue)
}


/// Creates a new throwing stub with a default failure result.
///
/// - Parameters:
/// - defaultError: The error that the stub throws when its result queue is empty.
/// - resultQueue: A queue of call results to use. If empty, `defaultResult` is used.
public convenience init(
defaultError: ErrorType,
resultQueue: [Result<ReturnType, ErrorType>] = []
) {
self.init(defaultResult: .failure(defaultError), resultQueue: resultQueue)
}


/// The arguments of the stub’s recorded calls.
public var callArguments: [Arguments] {
return calls.map(\.arguments)
Expand Down Expand Up @@ -162,7 +188,7 @@ extension ThrowingStub where ReturnType == Void {
/// - Parameters:
/// - defaultError: The error that the stub will throw when the error queue is empty.
/// - errorQueue: A queue of errors to throw. If empty, `defaultError` is used instead.
public convenience init(defaultError: ErrorType?, errorQueue: [ErrorType?] = []) {
public convenience init(defaultError: ErrorType? = nil, errorQueue: [ErrorType?] = []) {
self.init(
defaultResult: defaultError.map(Result.failure(_:)) ?? .success(()),
resultQueue: errorQueue.map { $0.map(Result.failure(_:)) ?? .success(()) }
Expand Down Expand Up @@ -280,13 +306,3 @@ extension ThrowingStub.Call where ErrorType == Never {
}
}
}


// MARK: - ReturnType is Void and ErrorType is Never

extension ThrowingStub where ReturnType == Void, ErrorType == Never {
/// Creates a new stub with an empty tuple as the default return value.
public convenience init() {
self.init(defaultReturnValue: ())
}
}
36 changes: 36 additions & 0 deletions Tests/DevTestingTests/Stubbing/StubTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,42 @@ struct StubTests {
}


@Test
func initDefaultReturnValueSetsProperties() {
let defaultReturnValue = 10
let resultQueue: [Result<Int, HashableError>] = (0 ..< 5).map { (i) in
i.isMultiple(of: 2) ? .success(i) : .failure(.init(id: i))
}

let stub = ThrowingStub<String, Int, HashableError>(
defaultReturnValue: 10,
resultQueue: resultQueue
)

#expect(stub.defaultResult == .success(defaultReturnValue))
#expect(stub.resultQueue == resultQueue)
#expect(stub.calls.isEmpty)
}


@Test
func initDefaultErrorSetsProperties() {
let defaultError = HashableError(id: 7)
let resultQueue: [Result<Int, HashableError>] = (0 ..< 5).map { (i) in
i.isMultiple(of: 2) ? .success(i) : .failure(.init(id: i))
}

let stub = ThrowingStub<String, Int, HashableError>(
defaultError: defaultError,
resultQueue: resultQueue
)

#expect(stub.defaultResult == .failure(defaultError))
#expect(stub.resultQueue == resultQueue)
#expect(stub.calls.isEmpty)
}


@Test
func accessingProperties() {
let stub = ThrowingStub<String, Int, HashableError>(defaultResult: .success(0))
Expand Down
Loading