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
- solutions for the original problem (to get tests running again in the messy setup)
- solutions for the problem after refactoring (to get refactored tests building in the somewhat tidier setup)
- suggestions for build settings to verify or include in the description here, to get clearer on what's going wrong
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.
Original situation (very messy)
- project
myCompany
- app target
app
which builds moduleMyCompany
- contains both Swift and ObjC code, with dependencies both ways
- Defines Module = Yes, Product Module Name =
MyCompany
- test target
myCompanyTests
- Defines Module = No, Product Module Name =
MyCompany
- also contains both Swift and ObjC code
- Defines Module = No, Product Module Name =
- CocoaPods for external dependencies, also a bunch of internal Swift modules with dependencies managed by hand
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.
First attempt at "fix the obvious mistakes"
As a first attempt to tidy things up somewhat I've done the following:
- Remove all non-test files from the
myCompanyTests
target - Rename
myCompanyTests
Product Module Name toMyCompanyTests
- Add
@testable import MyCompany
in lots of swift tests
Then 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- the generated file
MyCompanyTests-Swift.h
includes a line@import MyCompany;
which looks very promising! - but that line fails with the error
Module 'MyCompany' not found
- the generated file
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.