2017-05-20 126 views
0

我可以模擬SKPhysicsContact對象來喂入-(void)didEndContact:(SKPhysicsContact *)contact方法嗎?或者還有其他技術可以在這裏使用嗎?有沒有辦法編寫一個`SKPhysicsContactDelegate`函數的測試?

class PhysicsTestCase: XCTestCase { 

    var physics: GamePhysics! 

    ... 

    func testCaseOfCollisionsHandling() { 

     let contact = SKPhysicsContact() 
     contact.bodyA = SKPhysicsBody(circleOfRadius: 10) // Error, 'bodyA' is get-only property 

     physics.didEnd(contact) // Physics conforms to `SKPhysicsContactDelegate` 
    } 

    ... 

} 

... 

// The class that is being tested 

class GamePhysics: NSObject, SKPhysicsContactDelegate { 

    // MARK: - SKPhysicsContactDelegate 

    func didBegin(_ contact: SKPhysicsContact) { 

     guard let nodeA = contact.bodyA.node, let nodeB = contact.bodyB.node else { 
      fatalError("No nodes in colliding bodies") 
     } 

     switch (nodeB, nodeA) { 

     case let (ball as LogicalBall, tile as LogicalTile): 
      // Performing some logic 

     ... 

     } 
    } 

    func didEnd(_ contact: SKPhysicsContact) { 

     ... 
    } 

    ... 
} 
+0

您可以創建一個小而項目和彼此的頂部初始化你的對象。應該在這種情況下調用'didEndContact'。 –

+0

你到底在做什麼?你爲什麼要設置物理體?這不是你永遠不會做的事情。 –

+0

我想寫一組測試,檢查我的'SKPhysicsContactDelegate'是否按預期工作。 – Zapko

回答

0

雖然,subclas由Jon Reid在https://stackoverflow.com/a/44101485/482853提出的演唱非常整齊,我沒有設法使它在這種特殊情況下工作,因爲SKPhysicsContact類本身難以捉摸。

這個問題是可以解決的方法是使用好老的目標C運行時:

func testBallsCollisionIsPassedToHandler() { 

    let ballAMock = LogicalBallMock() 
    let bodyA = SKPhysicsBody(circleOfRadius: 10) 
    bodyA.perform(Selector(("setRepresentedObject:")), with: ballAMock) // So the bodyA.node will return ballAMock 

    let ballBMock = LogicalBallMock() 
    let bodyB = SKPhysicsBody(circleOfRadius: 10) 
    bodyB.perform(Selector(("setRepresentedObject:")), with: ballBMock) // So the bodyB.node will return ballBMock 

    let contact = SKPhysicsContact() 
    contact.perform(Selector(("setBodyA:")), with: bodyA) 
    contact.perform(Selector(("setBodyB:")), with: bodyB) 

    physics.didEnd(contact) 

    // Assertions ...  

} 
0

當,因爲我們沒有自己的API,我們不能改變一個類型,該解決方案是使用遺留代碼技術子類並覆蓋方式:

class TestablePhysicsContact: SKPhysicsContact { 
    var stubbedBodyA: SKPhysicsBody? 

    override var bodyA: SKPhysicsBody { 
     return stubbedBodyA! 
    } 
} 

要使用這個你示例性測試:

func testCaseOfCollisionsHandling() { 
     let contact = TestablePhysicsContact() 
     contact.stubbedBodyA = SKPhysicsBody(circleOfRadius: 10) 

     physics.didEnd(contact) 

     // assert something 
    } 

有關這方面的技術,請參見http://qualitycoding.org/swift-partial-mock/

+0

嗨,喬恩,很榮幸能從你那裏得到答案:)我最近偶然發現了你的博客,並從中得到了一些好主意。謝謝! – Zapko

+0

不幸的是,您提出的解決方案不起作用。測試崩潰是因爲'SKPhysicsContact'是一個雨傘類,'contact'在運行時被證明是'PKPhysicsContact'類型,即使我們將它初始化爲TestablePhysicsContact。 – Zapko

+0

但是,謝謝你的想法!它非常整齊。我很想回避分類,甚至沒有想到這個技巧。 – Zapko

相關問題