使用 XCTAssertThrows 模拟进行 Swift 单元测试

Posted

技术标签:

【中文标题】使用 XCTAssertThrows 模拟进行 Swift 单元测试【英文标题】:Swift Unit testing with XCTAssertThrows analogue 【发布时间】:2014-06-05 06:05:49 【问题描述】:

在 swift 语言单元测试中是否有任何等效的检查抛出异常的方法?

例如我有一堂课:

class Square : NSObject

    let sideLength: Int

    init(sideLength: Int) 
        assert(sideLength >= 0, "Wrong initialization of Square class with below zero side length")
        self.sideLength = sideLength
        super.init()
    

并测试以检查它是否有效。在目标 C 中,我可以编写这样的测试方法:

- (void)testInitializationWithWrongSideLengthThrowsExceptions
   XCTAssertThrows([[Shape alloc] initWithSideLength: -50], "Should throw exceptions on wrong side values initialisations");

什么是 Swift 平等技术?

【问题讨论】:

@Vignesh Kumar:请完全停止重新标记 Swift 问题。你没有帮助。完全没有。 【参考方案1】:

如果您将以下三个文件添加到您的测试中:

//  ThrowsToBool.h
#import <Foundation/Foundation.h>

/// A 'pure' closure; has no arguments, returns nothing.
typedef void (^VoidBlock)(void);

/// Returns: true if the block throws an `NSException`, otherwise false
BOOL throwsToBool(VoidBlock block);


//  ThrowsToBool.m
#import "ThrowsToBool.h"

BOOL throwsToBool(VoidBlock const block) 
    @try 
        block();
    
    @catch (NSException * const notUsed) 
        return YES;
    
    return NO;



// xxxTests-Bridging-Header.h
#import "ThrowsToBool.h"

然后你可以写:

XCTAssert(throwsToBool 
   // test code that throws an NSException
)

但它不适用于断言或前置条件:(

PS 我的想法来自:http://modocache.io/xctest-the-good-parts

【讨论】:

【参考方案2】:

我认为assert()-function 应该只用于调试目的。不仅是因为来自 Apple 的 Swift-Book (https://itun.es/de/jEUH0.l) 的以下声明:

“断言会导致您的应用终止,并且不能替代以不太可能出现无效条件的方式设计您的代码。”

这就是为什么我会这样解决这个问题:

import Cocoa
import XCTest

class Square

    let sideLength: Int

    init(_ sideLength: Int)
    
        self.sideLength = sideLength >= 0 ? sideLength : 0
    


class SquareTests: XCTestCase

    override func setUp()  super.setUp() 
    override func tearDown()  super.tearDown() 

    func testMySquareSideLength() 
        let square1 = Square(1);
        XCTAssert(square1.sideLength == 1, "Sidelength should be 1")

        let square2 = Square(-1);
        XCTAssert(square2.sideLength >= 0, "Sidelength should be not negative")
    


let tester = SquareTests()
tester.testMySquareSideLength()

【讨论】:

【参考方案3】:

swift 中没有与 XCTAssertThrows 等效的功能。现在你不能使用原生函数,但是有一个带有一些 Objective-C 帮助的解决方案。您可以使用 Quick,或仅使用 Nimble。或者制作自己的断言函数 - 参见这篇文章 - http://modocache.io/xctest-the-good-parts - 潜在改进 #2:将 XCTAssertThrows 添加到 Swift

【讨论】:

【参考方案4】:

我认为最好的方法是添加一座桥。

请看https://gist.github.com/akolov/8894408226dab48d3021

它对我有用。

【讨论】:

【参考方案5】:

Swift 2 中的正确方法:

class Square : NSObject

    let sideLength: Int

    init(sideLength: Int) throws  // throwable initializer
        guard sideLength >= 0 else  // use guard statement
           throw ...// your custom error type
        

        self.sideLength = sideLength
        super.init()
    

和测试:

func testInitThrows() 
        do 
            _ = try Square(sideLength: -1) // or without parameter name depending on Swift version
            XCTFail()
         catch ...  // your custom error type

         catch 
            XCTFail()
        
    

【讨论】:

以上是关于使用 XCTAssertThrows 模拟进行 Swift 单元测试的主要内容,如果未能解决你的问题,请参考以下文章

XCTAssertThrows具体例子

XCTAssertThrows 在断点处停止

使用Socket简单模拟C/S消息传递——Java(31)

Marvolo Gaunt's Ring(巧妙利用前后缀进行模拟)

使用spring嵌入式ldap模拟活动目录进行集成测试

2019.10.26模拟赛