Is there a best practice to change the Container configuration in a XCode UI Test, to mock for example a RestClient-Class that implements a Protocol that I could mock?
What I do is I pass a launch argument to the app in my UI test target. In my app's AppDelegate, I process this argument from ProcessInfo.processInfo.arguments.
If I find my UITest argument, I apply a special UI test assembly to my assembler which overrides all of the registries I'd like to mock out for UI tests. I also make sure to apply the test assembly after all my main assemblies are applied.
Thanks @thalmicMark for the nice practice. I've never tried Swinject with Xcode UI Test. @thalmicMark's practice is the best practice as far as I know. @sialcasa, did it fit in your case?
Please feel free to reopen this issue if the practice didn't fit in your case.
@thalmicMark can you provide an example of how this works for you? i'm embarking on a simliar ui test journey.
Sure thing. I've got a MainAssembler class where I apply all my Assemblies in the constructor. The MainAssembler class is instantiated by my AppDelegate.
class MainAssembler {
let assembler: Assembler
init() {
assembler = Assembler(container: SwinjectStoryboard.defaultContainer)
assembler.apply(assemblies: MyAssemblies.assemblies)
// Apply UITest Assemblies after applying regular assemblies to achieve overwriting of
// registrations.
let processInfo = ProcessInfo.processInfo
if processInfo.arguments.contains("UITests") {
assembler.apply(assemblies: UITestAssemblies.assemblies)
}
}
}
// I use non-instantiatable structs to achieve namespacing.
struct UITestAssemblies {
// Static property to hold all my assemblies for organizational purposes.
static let assemblies: [AssemblyType] = [...]
private init() { }
}
@UIApplicationMain
class AppDelegate: UIResponder {
let mainAssembler = MainAssembler()
}
Then, in my UI Tests, I set the launch argument:
class MyUITest: XCTestCase {
let app = XCUIApplication()
override func setUp() {
super.setUp()
continueAfterFailure = false
app.launchArguments.append("UITests")
app.launch()
}
}
You can organize your Assemblies however you want, but the main point is to use the launch argument to trigger your UITest assemblies to override certain registrations when performing UITests.
Most helpful comment
Sure thing. I've got a
MainAssemblerclass where I apply all my Assemblies in the constructor. TheMainAssemblerclass is instantiated by myAppDelegate.Then, in my UI Tests, I set the launch argument:
You can organize your Assemblies however you want, but the main point is to use the launch argument to trigger your UITest assemblies to override certain registrations when performing UITests.