带信号量的 XCTest 单一异步设置

Posted

技术标签:

【中文标题】带信号量的 XCTest 单一异步设置【英文标题】:XCTest Single Asynchronous SetUp With Semaphores 【发布时间】:2017-04-26 14:09:56 【问题描述】:

我正在通过 Alamofire 测试 API。我需要对服务器进行一次调用,以便为集成测试做好准备。完成后,我就可以开始运行测试了。

每次测试都会运行通常的override setUp(),所以我不想这样做。

因此,我选择覆盖class setUp(),如下所述:https://developer.apple.com/reference/xctest/xctestcase

这一切都很好,但是现在,我不能再使用标准的waitForExpectations。 (在class override setUp()) 中,我收到几个编译器错误,告诉我我不再调用相同的waitForExpectations,因为我在类方法中,而不是测试用例中。

为了解决这个问题,我想使用这样的信号量:

class ServiceLayerTests: XCTestCase 
    static var apiService: APIService = APIService()
    let sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: ["http://localhost:3000/": .disableEvaluation]))
    static var companyManger: UserWebResource?
    static var companyManagerID = -1
    override class func setUp() 
        apiService.baseURL = "http://localhost:3000/"
        beginIntegrationTests()
    

    class func beginIntegrationTests() 
        var semaphore = DispatchSemaphore(value: 0)
        apiService.beginIntegrationTests(completion: resource, error in
            if let resource = resource 
                if let manager = resource as? UserWebResource 
                    companyManger = manager
                    companyManagerID = manager.id
                    semaphore.signal()

                
            
        )
        _ = semaphore.wait(timeout: DispatchTime.distantFuture)
  

这不起作用。在后台,有一个对服务器的 alamo fire 调用,它会响应用户以用于集成测试。我确实看到服务器在旋转,所以我知道实际的通信正在发生,但我从未进入完成关闭。

我怀疑我不了解 Swift 是如何处理信号量的,并且我以某种方式造成了死锁。如果有人有更好的解决方案,我会很高兴听到它。

【问题讨论】:

仍在等待更好的解决方案。在类设置中调用等待似乎是合理的。 【参考方案1】:

我收到几个编译器错误,告诉我我不再调用 相同的waitForExpectations 因为我在一个类方法中,而不是一个 测试用例

这是有道理的。您可能想要的是重构,以便您处于测试用例中:

override class func setUp() 
    apiService.baseURL = "http://localhost:3000/"


func testIntegrationTests() 
    let urlExpectation = expectation(description: "INTEGRATION TEST")
    apiService.beginIntegrationTests(completion: resource, error in
        // ...
        urlExpectation.fulfill()
    )

   // not sure what an acceptable timeout would be, I chose this at random
   waitForExpectations(timeout: 25)  error in
       if let error = error 
           print("Error: \(error.localizedDescription)")
       
   

可以在此处找到带有一些良好测试示例的最佳资源之一:http://nshipster.com/xctestcase/

【讨论】:

有什么方法可以保证这个测试首先运行?强迫其他测试依赖于这个测试在它们运行之前完成,这感觉有点好笑。 @Mizmor 如果您使用的是XCode 8, no。 我希望有更好的方法,但这似乎是唯一的选择。谢谢【参考方案2】:

您可以将期望创建为一个惰性变量,它执行您的一次性设置并在完成时实现。

在您的 per-test setUp() 函数开始时,您可以等待该期望。

在完成之前,您的任何测试都不会运行,并且初始设置只会运行一次。

class WaitForSetup_Tests: XCTestCase 

    lazy var initialSetupFinished: XCTestExpectation = 
        let initialSetupFinished = expectation(description: "initial setup finished")

        initialSetupTask()  // your setup task that executes this closure on completion
            initialSetupFinished.fulfill()
            return
        

        return initialSetupFinished
    ()

    override func setUp() 
        wait(for: [initialSignOutFinished], timeout: 2.0)
        // do your per-test setup here
    

注意:此解决方案避免使用 override class function setUp() 类方法,因为除了在实例中之外,我无法弄清楚如何使用期望。

【讨论】:

以上是关于带信号量的 XCTest 单一异步设置的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信--信号(进程间通信唯一的异步方式)

Qt信号与槽函数问题

CS5213 HDMI转VGA带音频信号输出方案

异步通信之 信号

单元测试不了解 XCTest 期望的异步 UI 代码?

python 管道 事件 信号量 进程池(map/同步/异步)回调函数