我有一个从字典创建JSON数据的函数,并指定了它throws
以便将错误传播到堆栈:
func createBodyDataFrom(dictionary: [String: Any]) throws -> Data {
let bodyData = try JSONSerialization.data(withJSONObject: dictionary, options: [])
return bodyData
}
但是根据XCode,使用XCTAssertThrowsError
进行测试时,我遇到了测试失败,因为该函数引发了异常
func testCreateJSONFrominValidDictionaryThrows() {
let validDictionary: [String: Any] = [
"object": NSObject()
]
XCTAssertThrowsError(try testClient.createBodyDataFrom(dictionary: validDictionary))
}
IDE的失败消息显示:
XCTAssertThrowsError失败:在JSON写入(NSObject)中抛出无效类型
这似乎是矛盾的,但是如果不测试失败案例就感到不完整。有什么想法怎么了吗?
答案 0 :(得分:-1)
让我们从在Objective-C中运行一些等效的代码开始,以便我们在这里了解Cocoa的作用:
NSDictionary* d = @{@"Howdy": [NSObject new]};
NSError* err;
[NSJSONSerialization dataWithJSONObject:d options:0 error:&err];
NSLog(@"%@", err);
如果这是导致NSError的事情,我们将能够读取err
的值并将其打印到控制台。但这不是,我们不能。我们从未接触过NSLog语句。而是,程序意外崩溃:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Invalid type in JSON write (NSObject)'
1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48
2 Foundation 0x00007fff2580cb68 -[_NSJSONWriter writeRootObject:toStream:options:error:] + 0
3 Foundation 0x00007fff2580ff03 ___writeJSONObject_block_invoke + 371
[and so on]
那不是 一个NSError。这是一个NSException。它们是完全不同的东西,基本上这意味着我们的程序崩溃了。这不是错误的一掷千金。是突然死亡。
这就是documentation警告我们会发生的事情。如果我们提供了无法转换为JSON的对象,则dataWithJSONObject:options:error
这个方法不会失败。而是崩溃了:
如果
obj
将不会产生有效的JSON,则会引发异常。此异常是在解析之前抛出的,它表示 programming 错误,而不是 internal 错误。 您在使用isValidJSONObject:
调用此方法之前,应检查输入是否会生成有效的JSON 。
(斜体字。)
因此,发现问题并防止崩溃的正确方法是先致电isValidJSONObject:
。 dataWithJSONObject:options:error
这个方法不会解决这类问题,只会返回NSError;它将杀死整个程序。
这就是您发生的事情。您对try JSONSerialization.data(withJSONObject:)
的呼叫不是 throw
。它只是崩溃了。您可以看到,如果您在实际的Swift应用程序中单独尝试它:
override func viewDidLoad() {
super.viewDidLoad()
do {
try testCreateJSONFrominValidDictionaryThrows()
} catch {
print("oops")
}
}
func createBodyDataFrom(dictionary: [String: Any]) throws -> Data {
let bodyData = try JSONSerialization.data(withJSONObject: dictionary, options: [])
return bodyData
}
func testCreateJSONFrominValidDictionaryThrows() throws {
let validDictionary: [String: Any] = [
"object": NSObject()
]
try createBodyDataFrom(dictionary: validDictionary)
}
我们运行该应用程序,会发生什么?我们不打印“哎呀”。相反,我们得到与Objective-C完全相同的崩溃。
您的案例也是如此。我们从来没有投掷,因为我们坠毁了。测试失败报告了这一事实。您的testClient
从您的身下摔了下来(也许您可以通过一些控制台操作来检测到此情况),并且由于我们从未抛出NSError,所以测试本身又以失败告终。
在这里,可可引发NSException和返回NSError之间的区别至关重要。只有后者认为Swift会抛出错误。前者是崩溃。例如参见
How can I throw an NSError from a Swift class and catch it in an Objective-C class?
Avoid handling all exceptions until they've reached a global handler