1

我正在对 Typhoon 程序集进行子类化,以便返回存根实现,用于单元测试目的。

我的程序集看起来像这样:

class RealAssembly : TyphoonAssembly {
  public dynamic func instanceToStubOut() -> AnyObject {
    return TyphoonDefinition.withClass(SomeRealWorldClass.self)
  }

  public dynamic func instanceToTest() -> AnyObject {
    return TyphoonDefinition.withClass(ClassToTest.self, configuration: { (definition : TyphoonDefinition!) -> Void in 
      definition.useInitializer("initWithObjectToStub:", parameters: { (initializer : TyphoonMethod!) -> Void in
        initializer.injectParameterWith(self.instancetoStubOut())
      })
    })
  }
}

我的测试类仅用于测试 type 的实例ClassToTest,并且我想使用初始化器注入的依赖于SomeRealWorldClass要存根的 type 对象来测试它。因此,我将 RealAssembly 子类化,以便将instanceToStubOut()其覆盖以返回我的存根对象。

class MyTestClass : XCTestCase {
  var assembly : TestAssembly!

  class TestAssembly : RealAssembly {
    override dynamic func instanceToStubOut() -> AnyObject {
      return TyphoonDefinition.withClass(TestClass.self)
    }
  }

  @objc
  class TestClass : NSObject, ClassToStubOut {
    func methodToStubOut() { /* do nothing */ }
  }

  override func setUp() {
    super.setUp()
    self.assembly = TestAssembly().activate()
  }

  override func tearDown() {
    self.assembly = nil
    super.tearDown()
  }

  func testStuff() {
    let testingInstance = self.assembly.instanceToTest()
    XCTAssertTrue(testingInstance.doStuff(), "doStuff returns true")
  }
}

我希望这会起作用,但事实并非如此。Typhoon 似乎注入了一个未初始化的对象,而不是调用 TestAssembly.instanceToStubOut()

难道我做错了什么?我应该采取不同的方法吗?

编辑:这里有一些代码可以粘贴到 Swift Playground 中来演示问题。最后一行显示c.otherInstance返回nil

import Typhoon

@objc
class BaseClass : NSObject {
    var otherInstance : OtherProtocol!

    func doIt() -> String {
        return self.otherInstance.doStuff()
    }
}

@objc
protocol OtherProtocol {
    func doStuff() -> String
}

@objc
class OtherImpl : NSObject, OtherProtocol {
    func doStuff() -> String {
        return "OtherClass"
    }
}

@objc
class StubClass : NSObject, OtherProtocol {
    func doStuff() -> String {
        return "Stubbed out"
    }
}

class BaseAssembly : TyphoonAssembly {
    dynamic func baseObject() -> AnyObject {
        return TyphoonDefinition.withClass(BaseClass.self,
            configuration: { (def : TyphoonDefinition!) -> Void in
            def.injectProperty("otherInstance", with: self.otherObject())
        })
    }

    dynamic func otherObject() -> AnyObject {
        return TyphoonDefinition.withClass(OtherImpl.self)
    }
}

var assembly = BaseAssembly()
assembly.activate()
var b = assembly.baseObject() as! BaseClass
b.doIt()

@objc
class TestAssembly : BaseAssembly {
    override func otherObject() -> AnyObject {
        return TyphoonDefinition.withClass(StubClass.self)
    }
}

var testAssembly = TestAssembly()
testAssembly.activate()
var c = testAssembly.baseObject() as! BaseClass
c.otherInstance // this shouldn't be nil
4

1 回答 1

1

编辑:

虽然修补是一种选择,正如下面@Herman 的回答中所述,但问题中尝试的是受支持的功能,但是有一个回归错误阻止它正常工作。

Typhoon 3.2.2 中修复了回归错误,因此现在修补和覆盖程序集再次成为针对特定用例配置 Typhoon 的选项。

打补丁

Typhoon 中有一个用于此目的的修补功能。看这里
例如:

class StubClass : NSObject, OtherProtocol {
    @objc func doStuff() -> String {
        return "Stubbed out"
    }
}

let assembly = BaseAssembly()
assembly.activate()
let b = assembly.baseObject() as! BaseClass
print(b.doIt())

let testAssembly = BaseAssembly().activate()
let patcher = TyphoonPatcher()
patcher.patchDefinitionWithSelector("otherObject") { () -> AnyObject! in
    return StubClass()
}

testAssembly.attachPostProcessor(patcher)
let c = testAssembly.baseObject() as! BaseClass
print(c.doIt())
于 2015-07-17T07:53:25.177 回答