⚒️

Flutterでmockitoのanalyzer互換エラーをローカルパッチで回避する方法

に公開

mockitoの5.4.5とanalyzer7.xで競合エラー発生

Flutterプロジェクトで mockito 5.4.5 を使用している際、Dart SDK 3.x + analyzer 7.x 環境下で以下のようなビルドエラーに遭遇することがあります。今回の僕のケースだと、auto_route_generator 9.0.0が依存関係でmockito 5.4.5を読み込むので、それに巻き込まれてビルドエラーが起きてました。

Building package executable... (6.0s)
 Built build_runner:build_runner.
 [INFO] Generating build script completed, took 655ms
 [WARNING] ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:845:23: Error: The argument type 'InterfaceElement' can't be assigned to the parameter type 'InterfaceElementImpl'.
  - 'InterfaceElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'InterfaceElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
         .getInterface(interfaceElement)
                       ^
 ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:1173:26: Error: Can't assign spread elements of type 'TypeParameterElement' to collection elements of type 'TypeParameterElementImpl'.
  - 'TypeParameterElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'TypeParameterElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
           ...classToMock.typeParameters,
                          ^
 ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:1174:15: Error: Can't assign spread elements of type 'TypeParameterElement' to collection elements of type 'TypeParameterElementImpl'.
  - 'TypeParameterElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'TypeParameterElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
           ...?aliasedElement?.typeParameters,
               ^
 ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:1180:27: Error: The argument type 'InterfaceElement' can't be assigned to the parameter type 'InterfaceElementImpl'.
  - 'InterfaceElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'InterfaceElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
             .getInterface(classToMock)
                           ^
 ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:1792:65: Error: The argument type 'InterfaceElement' can't be assigned to the parameter type 'InterfaceElementImpl'.
  - 'InterfaceElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'InterfaceElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
     final overriddenMethods = inheritanceManager.getOverridden2(class_, name);
                                                                 ^
 ../../.pub-cache/hosted/pub.dev/mockito-5.4.5/lib/src/builder.dart:1800:46: Error: The argument type 'InterfaceElement' can't be assigned to the parameter type 'InterfaceElementImpl'.
  - 'InterfaceElement' is from 'package:analyzer/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/dart/element/element.dart').
  - 'InterfaceElementImpl' is from 'package:analyzer/src/dart/element/element.dart' ('../../.pub-cache/hosted/pub.dev/analyzer-7.4.1/lib/src/dart/element/element.dart').
           overriddenMethod.enclosingElement3 as InterfaceElement, name);
                                              ^
 [INFO] Precompiling build script... completed, took 5.6s
 [SEVERE] Failed to precompile build script .dart_tool/build/entrypoint/build.dart.
 This is likely caused by a misconfigured builder definition.
 
 Failed to update packages.

これは mockitoanalyzer の内部実装に依存しているために発生する互換性の問題です。analyzerのダウングレードをしたらいいのかもしれないけど、修正地獄に陥るので、mockitoにローカルパッチを当てて修正するのが問題解決として妥当です。

✋ 解決策:mockito にローカルパッチを当てて使用する

1. mockito をプロジェクト内にコピーする

mkdir -p patched_packages/mockito
cp -r ~/.pub-cache/hosted/pub.dev/mockito-5.4.5/* patched_packages/mockito/

※Windowsの場合は %APPDATA%\Pub\Cache\hosted\pub.dev\mockito-5.4.5\* を利用してください。


2. builder.dart を修正

パス: patched_packages/mockito/lib/src/builder.dart

InterfaceElementInterfaceElementImpl にキャストするよう修正します。

修正前: 845行目

.getInterface(interfaceElement)

修正後:

.getInterface(interfaceElement as InterfaceElementImpl)

修正前:1790行目

final overriddenMethods = inheritanceManager.getOverridden2(class_, name);

修正後:

final overriddenMethods = inheritanceManager.getOverridden2(class_ as InterfaceElementImpl, name);

修正前:1798行目

overriddenMethod.enclosingElement3 as InterfaceElement, name);

修正後:

overriddenMethod.enclosingElement3 as InterfaceElementImpl, name);

なお、exampleとtestディレクトリはエラーが出るので削除。必要に応じて、ヘッダーの外部読み込み宣言で下記も追加

import 'package:analyzer/src/dart/element/element.dart';

3. pubspec.yaml にローカルパス指定を追加

dependency_overrides:
  mockito:
    path: patched_packages/mockito

4. キャッシュとロックファイルをクリアして再取得

rm pubspec.lock
flutter clean
flutter pub get

✅ 結果

この手順で mockito 5.4.5 を手元で修正し、CIやローカルでもビルドエラーなく使用できるようになります。CIで使うんであれば、patched_packages/mockitoをコミットしとく必要があります。


🔚 補足:なぜ起こるのか?

mockitoanalyzerprivate API(InterfaceElementImpl に依存しています。
Dart 3.x以降の analyzer 7.x では構造が変更され、互換性が失われたことで型の不一致エラーが発生しています。

このバグは公式Issueでも報告されています:
https://github.com/dart-lang/mockito/issues/656


📝 まとめ

対応方法 安定性 コメント
mockitoをローカルパッチする 最も確実。CIでも安定動作
mockitoのバージョンを下げる 他依存パッケージとの衝突に注意
修正版リリースを待つ × 不確実、時間がかかる可能性あり

困っている方の助けになれば幸いです 🙌

Discussion