Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation Performance Issues #335

Open
choule99 opened this issue Dec 20, 2022 · 2 comments
Open

Compilation Performance Issues #335

choule99 opened this issue Dec 20, 2022 · 2 comments

Comments

@choule99
Copy link

choule99 commented Dec 20, 2022

Introduction
I work on a fairly large swift project, composed of multiple modules, and one of our requirements is near total coverage, and swiftymocky has been a great help in achieving this kind of coverage.

But we are starting to see a major problem

Problem
The problem is that the Mock.generated.swift file has gotten really really large, and while the swift compiler compiles it without issue, the problem is that the single file is the main bottleneck of our testing suite, the file that currently is about 100 000 line of code long takes about 50 to 60 seconds to compile on the best machine we have. (considering that the build, without the tests takes about 30 seconds)

While the mock file is getting compiled, all the 20 cores of the machine are mostly idle except for the 1 core that is actually compiling the mocks. Once complete, xcode gets back on track, and successfully parallelize the rest of the build.

Suggestion
Give us a way to split the Mock.generated.swift into multiple files, something like X mocks per file (where X is configured by the project), so instead of 1 giant swift file, we have X multiple smaller files that xcode can parallelize using all the available cores.

So if I had an original file with 50 mocks in it, and configure X to 10, I would have 5 Mock.generated.swift files named like:

Mock.1.generated.swift
Mock.2.generated.swift
Mock.3.generated.swift
Mock.4.generated.swift
Mock.5.generated.swift

Pros
This I believe would be a major quality of life improvement, especially for large projects, with a lot of mockable protocols.

Cons
A project with a lot of mocks would have to import a lot of files.

@pschneider
Copy link

Might not be a direct solution to your project, but you could try to split the Mocks already based on your own definitions (e.g. data layers). The Mockfile supports this already. The trick is to have different files where your extensions with the //sourcery: AutoMockable annotations are declared.

Example:

Let's say you want to split based on an app layer for your "View Models" and "Repositories". Your Mockfile could look like this:

repositories:
  sources:
    include:
      - # path to your source code
      - # path to the file where your protocol extension with //sourcery: AutoMockable are declared containing ONLY repository types
  output: ./<DESTINATION_OF_MOCKED_GENERATED/MockedRepositories.generated.swift
  targets:
  - # your test target
  testable:
  - # your testable import
  import:
  - # list of imports that are required in the mock to compile (e.g. Foundation)

viewModels:
  sources:
    include:
      - # path to your source code
      - # path to the file where your protocol extension with //sourcery: AutoMockable are declared containing ONLY view model types
  output: ./<DESTINATION_OF_MOCKED_GENERATED/MockedViewModels.generated.swift
  targets:
  - # your test target
  testable:
  - # your testable import
  import:
  - # list of imports that are required in the mock to compile (e.g. Foundation)

Result will be that MockedViewModel.generated.swift will only contain mocks related to the view models and MockedRepositories.generated.swift will contain only mocks for the repositories.

You could of course just model a Mockfile like in your example and name the declarations based on numbers and split your //sourcery: Automockable declarations equally between all of them.

Of course that requires some setup and is not automated, but I think it should already help you.

@choulepoka
Copy link

I actually added a post-generation command-line utility that takes the gigantic Mocks.generated.swift, and split it in a 1-mock per file fashion, and it's very effective.

As a bonus, Github no longer stalls with out-of-memories when diffing the generated code in a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants