Using Selective Testing With a Decoupled Module Architecture

Question or problem

I have been considering using Tuist was a way to improve feedback on PRS.
Ideally I’d like to make use of the selective testing feature, which I understand will run tests when either the hash of the tests in a module change, or if the hash of tests of a module that my module depends on changes.
described here: xcodebuild · Selective testing · Develop · Guides · Tuist

This makes sense, but when this is used with a project that uses Modular architecture and dependency inversion, then modules (deliberately) do not depend directly on other modules. The dependencies are abstracted through a ‘contract’ interface. In this case I don’t see how the default logic in selective testing can ensure the correct tests are run when the project changes.

Modular architecture and dependency inversion described: Dependency Inversion as a Driver to Scale Mobile Development | SoundCloud Backstage Blog

Using the example from Soundcloud blog linked in

I have 3 modules:
Payment - Needs to use Authentication, depends on AuthenticatingContract as an abstraction
AuthenticatingContract - Defines the protocol used by Payment
Authentication - Implements AuthenticatingContract

If the implementation of AuthenticatingContract changes (eg in the Authentication module), I would like the Payment UI Tests to be run. However, Payment depends on AuthenticatingContract, and this hasn’t changed, so the selective testing process from Tuist would not help me.

Please can you let me know how it can be possible to achieve this, eg is there a way to write my own selective testing rules? Can I detect if a module implements a contract, and then test all consumers of that contract when the implementation changes?

Expectation

It would be great if there was a supported way to achieve selective testing when the project architecture uses The Modular Architecture and dependency inversion between modules as described in your documentation.

Hi @MikeB

Welcome to the forum and thanks for moving the discussion here.

Building on your example, if your PaymentUITests depend on a concrete implementation of AuthenticationContract, Authentication, you’ll declare that as a dependency and therefore, if the implementation of Authentication changes, PaymentUITests will run too.

Would that make sense?

Hi @pepicrft,

Thanks for your reply, yes I think that makes sense.

So even though my Payment module doesn’t depend directly on the Authentication implementation, when I run my UITests for Payment feature, I build a testing target that does depend on the Authentication module.

I can see how this would work, thanks!

Do you have any examples of Project.swift manifests that have modules using this approach by any chance? Eg where the UI Tests for a feature depend on an implementation of a contract that is not included in the feature?

Thanks,

Mike

Hi @MikeB

We don’t have any example that I can point you to, but in terms of definition, you should be able to declare those dependencies with the generated projects DSL:

let target = Target(
   name: "PaymentUITests",
   product: .uiTests,
   dependencies: [
      .target(name: "Authentication")
   ] 
)