I've got a mixed ObjC/Swift codebase with a very mixed-up structure, and the tests no longer run under Xcode 10.2 (details below). I'm trying to make the minimum structural changes to get tests back, so that I have a safety net for the refactoring that will come next. After taking what seems to me to be the obvious first step, the tests fail to build (details again below).
I'm interested in any of
I'm not interested in advice about how to structure a fresh project or create new targets with more sensible configurations: extracting code from these targets is also non-trivial, so I really need test coverage back before I start any refactoring.
myCompany
app
which builds module MyCompany
MyCompany
myCompanyTests
MyCompany
Test files are included only in the myCompanyTests
target, but many code files are included in both app
and myCompanyTests
targets. I think this and the two targets defining the same module name was probably in order to avoid having to import the app target into tests, because of problems with Swift/ObjC interop (see the next section). Building tests produces warnings about classes implemented in two places:
objc[9724]: Class _TtC12MyCompany12DiaryFetcher is implemented in both
/Users/tikitu/Library/Developer/CoreSimulator/Devices/556CAC28-B90B-4B6B-A87C-1A1450795051/data/Containers/Bundle/Application/495F33C2-F7FC-4AE6-B3FE-6908D6361B55/mycompany-develop.app/mycompany-develop (0x10d724060)
and
/Users/tikitu/Library/Developer/Xcode/DerivedData/mycompany-bifciplpbqaeqqdrmhivpjgnojri/Build/Products/Debug-iphonesimulator/mycompany-develop.app/PlugIns/myCompanyTests.xctest/myCompanyTests (0x13566dc38).
One of the two will be used. Which one is undefined.
As of Xcode 10.2, myCompanyTests
builds successfully but running the tests fails with an EXC_BAD_ACCESS
in swift_checkMetadataState
somewhere inside the UIApplicationMain
call. My guess is that this is related to the module-name/files-in-both-targets shenanigans.
As a first attempt to tidy things up somewhat I've done the following:
myCompanyTests
targetmyCompanyTests
Product Module Name to MyCompanyTests
@testable import MyCompany
in lots of swift testsThen I start running into Swift/ObjC interop problems, because I need to call Swift code in the app target from ObjC code in the test target. Things I've tried:
#import "MyCompany-Swift.h"
in an objc .m test file
'MyCompany-Swift.h' file not found
#import <MyCompany-Swift.h>
in an objc .m test file
'MyCompany-Swift.h' file not found
#import <MyCompany/MyCompany-Swift.h>
in an objc .m test file (yes you can see I don't actually understand this mechanism)
'MyCompany/MyCompany-Swift.h' file not found
#import "MyCompanyTests-Swift.h"
in all objc .m test files that need access to the app target
MyCompanyTests-Swift.h
includes a line @import MyCompany;
which looks very promising!Module 'MyCompany' not found
Especially this last one looks suspicious to me, as I would expect the Xcode generated file should "just work". I guess I've overridden some user setting somewhere that's getting in the way: I'd be delighted with any suggestions for places to check.
I believe the issue to be that only a framework target auto-creates the swift-to-objc header file Module-Swift.h
: neither the app target nor a test target appear to do so.
I successfully resolved these issues by creating two new framework targets
* MyCompanyStuffThatUsedToBeInApp
(containing everything that used to be in the app target except main.h
), which does bidirectional swift/objc interop and
* MyCompanyTesting
(a framework target imported by the tests, which likewise does bidirectional swift/objc interop for test-only code).
There may still be simpler ways to tidy this up, but this one at least is proven to work.