Googling has led me to general Swift error handling links, but I have a more specific question. I think the answer here is "no, you're out of luck" but I want to double check to see if I'm missing something. This question from a few years ago seems similar and has some answers with gross looking workarounds... I'm looking to see if the latest version of Swift makes something more elegant possible.
Situation: I have a function which is NOT marked with throws
, and uses try!
.
Goal: I want to create a unit test which verifies that, yep, giving this function the wrong thing will in fact fail and throw a (runtime/fatal) error.
Problems:
XCTAssertThrows
also does not catch the error.This function is built to have an identical signature to another, silently failing function, which I swap it out for this one on simulators so that I can loudly fail during testing (either automated or manual). So I can't just change this to a throwing function, because then the other function will have to be marked as throwing and I want it to fail silently.
So, is there a way to throw an unhandled error that I can catch in a unit test?
Alternatively, can I make this function blow up in a testable way without changing the signature?
Unit testing considerations What errors are commonly found during Unit Testing? (1) Misunderstood or incorrect arithmetic precedence, (2) Mixed mode operations, (3) Incorrect initialization, (4) Precision inaccuracy, (5) Incorrect symbolic representation of an expression.
To create new unit case in iOS, go to File -> New -> File, and then select Unit Test Case Class. Doing so creates a template just like the one you got with your project. In our case, we want to name the file to correspond with the new Pokemon-related data structures we have introduced.
Overview. Use the XCTest framework to write unit tests for your Xcode projects that integrate seamlessly with Xcode's testing workflow. Tests assert that certain conditions are satisfied during code execution, and record test failures (with optional messages) if those conditions aren't satisfied.
The really short version is that unit tests have access to the code in your app (or whatever kind of module you are building) and UI tests do not have access to the code. A unit test only tests one single class per test.
There is no way to catch non-throwing errors in swift and you mean that by using !
after try
.
But you can refactor your code in a way you can have more control from outside of the function like this:
func throwingFunc() throws {
let json = "catch me if you can".data(using: .utf8)!
try JSONDecoder().decode(Int.self, from: json)
}
func nonThrowingFunc( catchHandler:((Error)->Void)? = nil ) {
guard let handler = catchHandler else { return try! throwingFunc() }
do {
try throwingFunc()
} catch {
handler(error)
}
}
So the handler will be called only if you are handling it:
// Test the function and faild the test if needed
nonThrowingFunc { error in
XCTFail(error.localizedDescription)
}
And you have the crashing one:
// Crash the program
nonThrowingFunc()
!
(as force) is designed for situations that you are pretty sure about the result. good examples:
If your function is not pure enough and may fail by passing different arguments, you should consider NOT forcing it and refactor your code to a safer version.
Swift (until & including current 5.5) postulates explicitly that all errors inside non-throwing function MUST be handled inside(!). So swift by-design has no public mechanism to intervene in this process and generates run-time error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With