简体   繁体   中英

Swift: Array of base class does not call subclass function implementation

I'm trying to inject a fake instance into a unit test for a class depending on SimplePing, a NSObject subclass. My class has a property var simplePings: [SimplePing] which in my unit test I set as an array of FakeSimplePing. However, when the class goes in the array and calls simplePing.start() , it calls the SimplePing.start implementation instead of FakeSimplePing's, even though when I debug I see that the instance type is FakeSimplePing.

When the property is just a single SimplePing, the unit test uses the FakeSimplePing.start and the test passes. Does this have something to do with Swift and arrays of superclasses?

class Pinger : NSObject {
   private var simplePings: [SimplePing] = []

   func pingLocation(location: Location) -> Signal<Double, NoError> {
       let simplePings = location.serverIPs.map { (serverIP: String) -> SimplePing in
           let simplePing = SimplePing(hostName: serverIP)
           simplePing?.delegate = self
           return simplePing
    }
       configureDependencies(simplePings)
       simplePings.forEach { $0.start() }

       return signal
   }

   func configureDependencies(simplePings: [SimplePing]) {
       if self.simplePings.isEmpty {
           self.simplePings = simplePings
       }
   }
}



class FakeSimplePing: SimplePing {
    var receivedStart = false
    var receivedSendPingWithData = false
    var fakeHostName: String!
    override var hostName: String {
        return fakeHostName
    }

    convenience init(hostName: String) {
        self.init()
        fakeHostName = hostName
    }

    override func start() {
        // This does not get called
        receivedStart = true
        delegate?.simplePing?(self, didStartWithAddress: nil)
        delegate?.simplePing?(self, didReceivePingResponsePacket: nil)
    }

    override func sendPingWithData(data: NSData!) {
        receivedSendPingWithData = true
    }
}

And the failing test:

            beforeEach {
                fakeSimplePing = FakeSimplePing(hostName: serverIP)
                fakeSimplePing.delegate = pinger
                pinger.configureDependencies([fakeSimplePing])
            }

            it("pings server with data") {
                pinger.pingLocation(location)

                expect(fakeSimplePing.receivedSendPingWithData).toEventually(beTrue())
            }

The problem (I believe...) is in the naming in pingLocation

in the line

let simplePings = location.serverIPs.map { .... 

you use the same name as of your property

private var simplePings: [SimplePing] = []

so you may think you're defining a new variable with the let , but actually, you may just use your property and change it on the way, so it got changed to SimplePing array, as it returns from the map

try to change your method into:

func pingLocation(location: Location) -> Signal<Double, NoError> {
       let tempSimplePings = location.serverIPs.map { (serverIP: String) -> SimplePing in
           let simplePing = SimplePing(hostName: serverIP)
           simplePing?.delegate = self
           return simplePing
    }
       configureDependencies(tempSimplePings)
       simplePings.forEach { $0.start() }

       return signal
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM