1

I'm using Quick to test my Swift code. However, I think it doesn't release objects defined in describe scope:

class MyClass {
    deinit {
        print(self, #function)
    }
}

final class MyClassSpec: QuickSpec {
    override func spec() {
        describe("") {
            let foo = MyClass()
            it("") {
                print(foo)
                expect(true).to(beTrue())
            }
        }
    }
}

I don't see any output from print inside deinit, and a debug breakpoint inside the deinit does not get catched. If I move foo inside it, the deinit is called.

Is this a bug in Quick, or is it normal for deinit not to be called in a test suite?

Jay Lee
  • 1,684
  • 1
  • 15
  • 27

1 Answers1

1

Apparently the code I wrote was not only retaining the object but was also an anti-pattern.

Even a plain old XCTestCase retains an object:

class MyClass {
    deinit {
        print(self, #function)
    }
}

final class MyClassTest: XCTestCase {
    let foo = MyClass()

    func testMyClass() {
        print(foo)
        XCTAssert(true)
    }
}

deinit is not called for foo.

This is due to a nature of XCTestCaseit never really gets deinited. So one should always use setUp & tearDown to manage everything (or more accurately, objects with reference semantics).

I believe this directly translates to QuickSpec as well, so I should always use beforeEach & afterEach in order to manage the objects. To "fix" the problem, I should test like:

final class MyClassSpec: QuickSpec {
    override func spec() {
        describe("") {
            let foo: MyClass!

            beforeEach { foo = MyClass() }
            afterEach { foo = nil }

            it("") {
                print(foo)
                expect(true).to(beTrue())
            }
        }
    }
}
Jay Lee
  • 1,684
  • 1
  • 15
  • 27
  • 1
    I've had exactly the same problem and I've been unable to find many resources on the web relating to memory management in Quick specs. I've put together a very simple spec to test this out and my own findings seem to mirror yours. It looks like the behaviour does mimic that of XCTest. So unless anyone else has a better suggestion than implementing `afterEach` for every allocation, I'm going to roll with that – Trebor Sep 22 '20 at 10:45