介绍

NCrunch 是一款在 Visual Studio 下自动化且并行的单元测试工具,可以在输入代码且未保存的情况下检测单元测试代码是否存在问题。

问题

Unity 可以使用 Visual Studio 打开生成的解决方案,NCrunch 却无法正常工作,会报以下错误:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
An error occurred while analysing this project after it was built: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Unable to cast object of type 'nCrunch.Module.NUnit3.Integration.NUnit3CallbackProxy' to type 'System.Web.UI.ICallbackEventHandler'.
   at NUnit.Framework.Api.FrameworkController.LoadTestsAction..ctor(FrameworkController controller, Object handler)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeConstructor(Object[] args, SignatureStruct& signature, IntPtr declaringType)
   at System.RuntimeMethodHandle.InvokeConstructor(Object[] args, SignatureStruct signature, RuntimeTypeHandle declaringType)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at nCrunch.Module.NUnit3.Integration.FrameworkController.LoadTests(INUnit3CallbackHandler handler)
   at nCrunch.Module.NUnit3.Integration.NUnit3FrameworkInteractor.<prepareFramework>b__7_0()
   at nCrunch.Common.PerformanceTracking.PerfTracker.TrackActivity(String name, Action activity)
   at nCrunch.Common.PerformanceTracking.PerfTracker.TryTrackActivity(String name, Action activity)
   at nCrunch.Module.NUnit3.Integration.NUnit3FrameworkInteractor.prepareFramework(DynamicProxy[] dynamicProxies)
   at nCrunch.Module.NUnit3.Integration.NUnit3FrameworkInteractor..ctor(ReflectedAssembly assembly, IList`1 referencedAssemblyFilePaths, ComponentUniqueName testComponentUniqueName, DynamicProxy[] dynamicProxies)
   at nCrunch.Module.NUnit3.Integration.NUnit3FrameworkRuntimeEnvironment.FindFrameworkTestsInAssembly(ReflectedAssembly assembly, FilePath assemblyFilePath, IList`1 referencedAssemblyFilePaths, ComponentUniqueName testComponentUniqueName, PlatformType platformType, DynamicProxy[] dynamicProxies)
   at nCrunch.TestExecution.TestFinder..()
   at nCrunch.Common.PerformanceTracking.PerfTracker.TrackActivity(String name, Action activity)
   at nCrunch.TestExecution.TestFinder..()
   at nCrunch.Common.PerformanceTracking.PerfTracker.TrackActivity(String name, Action activity)
   at nCrunch.TestExecution.TestFinder.FindTestsForFrameworks(ReflectedAssembly assembly, FilePath assemblyFilePath, IList`1 referencedAssemblyFilePaths, DescribedTestFrameworkDiscoverer[] describedDiscoverers, ComponentUniqueName testComponentUniqueName, PlatformType platformType, DynamicProxy[] dynamicProxies)
   at nCrunch.TestExecution.RemoteTaskRunner.AnalyseAssembly(DescribedTestFrameworkDiscoverer[] applicableFrameworks, ComponentUniqueName testComponentUniqueName, PerfTracker perfTracker)

是由于 Unity 使用了自定义的 NUnit 3.5.0 版本,其中存在与正常 NUnit API 不兼容的代码。NCrunch 开发者解释道,Build failed on Unity project - Build/Test Issues - NCrunch Forum

思路

由于 Unity 并不使用生成的项目文件,所以可以直接将项目文件中对 Unity 自定义 NUnit 的引用修改为官方正常版本的引用即可。

  • OnGeneratedCSProjectFiles() 事件中无论对项目文件做是否一样的修改都会触发 Visual Studio 重新加载解决方案,放弃此方法。
  • ProjectFilesGenerator.ProjectFileGeneration 事件中处理是可以的,因为 Unity 内部也是使用此事件处理项目文件。

解决方案

将以下仓库克隆到 Assets/Plugins/Editor 目录中即可解决此问题:

GitHub - networm/NCrunchAdapterForUnity: Fix NCrunch didn’t work in project generated by Unity.