2017-05-20 128 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

相关问题