johnno1962 / injectionforxcode

Runtime Code Injection for Objective-C & Swift
MIT License
6.55k stars 565 forks source link

Do not lock main GCD when executing tests #234

Closed polac24 closed 6 years ago

polac24 commented 6 years ago

Currently, main GCD queue is blocked during tests what makes different context than standard XCTestCase.

Includes also minor bugfixing for unit testing python script:

polac24 commented 6 years ago

Hi @johnno1962! Over last 2 month I have been actively using unit tests support and despite 2 minor issues (that I fix by the way), I found quite significant and annoying one: unit tests cannot test asynchronous code with XCTest's expectations.

To reproduce, you can try pod: pod try InjectionTDD and inject source of InjectionTDDTests.swift. Test testMainQueueIsNotBlocked fails, while standard Xcode configuration leads to a success.

After investigation, I found out that Apple does not execute tests on a main GCD queue, yet still on main Thread. Therefore, XCTestCase's waitForExpectations(timeout:handler:) loops RunLoop and tested code can still leverage dispatching on a main queue.

My fix for that creates a separate serial queue to ensure that injecting a new test classes while some previous tests are still running does not conflict with each other.

I found our that this fix requires to rebuild InjectionLoader.bundle and I could not find a way to build it without breaking XProbe support. I would be grateful, if you could rebuild it (unless it is not a problem) and/or accept. I wish to publish medium post about InjectionTDD (draft), but I was afraid "releasing" with described above bug could be a "false start".

By the way, I saw that your new Injection3 code includes the same issue (starting tests from a main GCD), maybe you can reconsider this part?

In case this PR isn't matching your expectations/plans, do you mind publishing "patched" Injection2.app (without Xprobe) on my releases tab?

johnno1962 commented 6 years ago

Hi @polac24, Thanks for this! I’ve updated InjectionTDD.app.zip with your changes on my site and worked it into “InjectionIII” https://github.com/johnno1962/InjectionIII/commit/356f3b5bd10a7439552d89df237b54c6f527ed25. Your medium post looks great though where it says "Swift uses also vtable and static dispatch, what makes runtime method swizzling impossible”, injection does patch the Swift vtable so if your class/method isn’t final it should inject.

polac24 commented 6 years ago

Thank you @johnno1962 for merge, update and feedback!!!

You are right, mae culpa. I completely forgot about magical memcpy, so I edited the post and left only static dispatch limitation.