NUnit 和测试 Xamarin PCL
NUnit and testing a Xamarin PCL
我正在开发便携式 class 库和 iOS 应用程序,其中数据访问基于 Paul Betts' ModernHttpClient, Fusillade, Refit and Akavache 库。这适用于 PCL 和 iOS 应用程序,但我在针对 PCL.
创建单元测试时遇到问题
如果我用Resharper test running within Visual Studio 2015 all my tests pass but if I run the NUnit tests in Xamarin Studio about half the tests fail with TypeLoadExceptions。我试图确定是哪个 dll 导致了我的问题,但据我所知,一切都应该如此。
PCLClass测试中
internal class ApiService<TRefitService> : IApiService<TRefitService> where TRefitService : IServiceContract
{
private readonly Lazy<TRefitService> background;
private readonly Lazy<TRefitService> userInitiated;
private readonly Lazy<TRefitService> speculative;
private ApiService(){}
public ApiService(string baseUrl)
{
ParameterGuard.ThrowIfNullOrEmpty(baseUrl, nameof(baseUrl));
Func<string, RateLimitedHttpMessageHandler, TRefitService> createClient = (address, handler) =>
{
HttpClient client = new HttpClient(handler) {BaseAddress = new Uri(address)};
return RestService.For<TRefitService>(client);
};
background = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Background)));
speculative = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Speculative)));
userInitiated = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.UserInitiated)));
}
/// <summary>
/// Use for network requests that are running in the background.
/// </summary>
public TRefitService Background => background.Value;
/// <summary>
/// Use to fetch data into a cache when a page loads. Expect that these requests will only get so far then give up and start failing.
/// </summary>
public TRefitService Speculative => speculative.Value;
/// <summary>
/// Use for network requests that are fetching data that the user is waiting on *right now*.
/// </summary>
public TRefitService UserInitiated => userInitiated.Value;
}
Xamarin Studio 测试失败
[Test()]
public void PassingInANullBaseUrlThrowsAnException()
{
Assert.Throws<ArgumentNullException>(() => new ApiService<IAuthorisationApi>(null));
}
测试结果
Expected: But was:
(Could not load type 'ApiService`1' from
assembly
'/Users/206474978/Desktop/test/test/test/bin/Debug/xxx.xxx.xxx.dll'.)
at NUnit.Framework.Assert.Throws (IResolveConstraint expression,
NUnit.Framework.TestDelegate code, System.String message,
System.Object[] args) <0x377c1c8 + 0x000e6> in :0
at NUnit.Framework.Assert.That (System.Object actual,
IResolveConstraint expression, System.String message, System.Object[]
args) <0x377c888 + 0x000bf> in :0 at
NUnit.Framework.Assert.Throws (IResolveConstraint expression,
NUnit.Framework.TestDelegate code, System.String message,
System.Object[] args) <0x377c1c8 + 0x00137> in :0
at NUnit.Framework.Assert.Throws (System.Type expectedExceptionType,
NUnit.Framework.TestDelegate code, System.String message,
System.Object[] args) <0x377bfc8 + 0x0004f> in :0
at NUnit.Framework.Assert.Throws[T] (NUnit.Framework.TestDelegate
code, System.String message, System.Object[] args) <0x377bf58 +
0x00033> in :0 at
NUnit.Framework.Assert.Throws[T] (NUnit.Framework.TestDelegate code)
<0x377bf08 + 0x0003b> in :0 at
test.Test+ApiServiceTest.PassingInANullBaseUrlThrowsAnException ()
[0x00001] in /Users/206474978/Desktop/test/test/test/Test.cs:37 at
(wrapper managed-to-native)
System.Reflection.MonoMethod:InternalInvoke
(System.Reflection.MonoMethod,object,object[],System.Exception&) at
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags
invokeAttr, System.Reflection.Binder binder, System.Object[]
parameters, System.Globalization.CultureInfo culture) [0x00038] in
/private/tmp/source-mono-4.2.3/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.3/mcs/class/corlib/System.Reflection/MonoMethod.cs:295
现在这通常不是问题,因为我只会使用整形器,但我正在 Jenkins 之上构建我们的持续集成管道,运行 通过 Xamarin 库中的 nunit 包进行测试,结果在构建报告失败中。
知道这里的问题是什么吗?
更新
好的,按照 SushiHangover 的提示,我使用了最新版本的 NUnit 测试运行器并得到了以下输出。似乎错误是 TypeLoadException 或 BadImageFormatException 但我不确定为什么。我检查了两个项目的输出,都设置为 AnyCPU。
[Test()]
public void PassingInAValidBaseAddressGivesAValidRefitUserInitiatedObject()
{
var api = new ApiService<IAuthorisationApi>(BaseAddress);
Assert.IsNotNull(api.UserInitiated);
}
[Test()]
public async Task PassingInAValidBaseAddressReturnsAValidAccountFromTheBackgroundObject()
{
//Arrange
ApiService<IAuthorisationApi> service = = new ApiService<IAuthorisationApi>(BaseAddress);;
//Act
AuthorisationDto account = await service.Background.GetAuthorisationToken(logonPost, "ireland");
//Assert
Assert.IsTrue(account != null);
}
Invalid type
xxx.xxx.Core.Services.Lib.ApiService`1
for instance field
xxx.xxx.Core.Tests.ApiServiceTest+c__async0:__0
7) Error : xxx.xxx.Core.Tests.ApiServiceTest.PassingInAValidBaseAddressGivesAValidRefitUserInitiatedObject
System.TypeLoadException : Failure has occurred while loading a type.
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x3083b38 + 0x00093> in <filename unknown>:0
8) Error : xxx.xxx.Core.Tests.ApiServiceTest.PassingInAValidBaseAddressReturnsAValidAccountFromTheBackgroundObject
System.BadImageFormatException : Could not resolve field token 0x040001ae
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x3083b38 + 0x00093> in <filename unknown>:0
更新 2
另一个测试因以下堆栈跟踪而失败,这看起来像是单声道的问题?
System.TypeLoadException : Could not load type 'ApiService`1' from
assembly
'/Users/206474978/Documents/Development/Projects/BRSMemberApp/UnitTests/BrsGolf.Members.Core.Tests/bin/Debug/Brs.Members.Core.dll'.
at (wrapper managed-to-native)
System.Reflection.MonoMethod:InternalInvoke
(System.Reflection.MonoMethod,object,object[],System.Exception&) at
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags
invokeAttr, System.Reflection.Binder binder, System.Object[]
parameters, System.Globalization.CultureInfo culture) [0x00038] in
/private/tmp/source-mono-4.2.3/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.3/mcs/class/corlib/System.Reflection/MonoMethod.cs:295
(这与我发布的旧 answer 有关)
安装的 Mono 框架包括相对较旧的 NUnit
版本(2.4.8 版)。该版本中有许多 issues/bugs,范围从不正确的异常捕获到 solution/project 解析问题。
我们为 OS-X 构建(包括 Jenkins CI)所做的是通过 nuget 安装最新的 NUnit 到我们的解决方案根目录,并将该安装用于本地测试构建工件。
类似于:
cd YourSolutionRootDir
nuget install nunit.runners
mono ./NUnit.ConsoleRunner.3.2.0/tools/nunit3-console.exe MyTestProject/bin/debug/except.dll
好的,
这是一个非常讨厌的人。该问题与 Mono 或 NUnit 都没有直接关系。尽管旧版本的 NUnit 导致了其他问题。
感谢@SushiHangover 给我的提示,让我开始解决这个问题。
最初我分解了单元测试以实例化 APIService class 的每个依赖项,这些依赖项最终在 iOS、PCL 上标记了 System.Net.Http dll 的问题和单元测试项目。似乎我正在实施的库之一引用了该库的 v1.5.0.0,导致项目版本不匹配,不正确的引用(.Net、PCL 等)加剧了这种情况。我通过在每个项目 app.config.
中包含一个特定的程序集绑定来解决这个问题
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
这解决了大约 80 个失败的单元测试,但仍然有大约 50 个失败。
进一步探索发现 PCL 和单元测试项目中的 Akavache 缓存库版本存在问题,该项目解决了另外 40 个单元测试。
最后,在单元测试项目中 运行ning Telerik 的 JustMock 库出现了一个问题,在测试 PCL 时,部分库似乎不受支持。我解决了这个问题,将 JustMock 换成最小起订量并重构了一些测试。这解决了 Xamarin Studio 剩余的失败单元测试。
然后我 运行 在构建服务器上进行这些测试并获得 80 个通过测试和 87 个未通过 运行。妈的
为了解决这个问题,我将 Xamarin v2.4.8 中的默认测试 运行ner 换成了最新下载的测试,现在所有单元测试都在构建服务器上通过了。
长话短说 当您遇到此类问题时,请检查您的参考资料。
我正在开发便携式 class 库和 iOS 应用程序,其中数据访问基于 Paul Betts' ModernHttpClient, Fusillade, Refit and Akavache 库。这适用于 PCL 和 iOS 应用程序,但我在针对 PCL.
创建单元测试时遇到问题如果我用Resharper test running within Visual Studio 2015 all my tests pass but if I run the NUnit tests in Xamarin Studio about half the tests fail with TypeLoadExceptions。我试图确定是哪个 dll 导致了我的问题,但据我所知,一切都应该如此。
PCLClass测试中
internal class ApiService<TRefitService> : IApiService<TRefitService> where TRefitService : IServiceContract
{
private readonly Lazy<TRefitService> background;
private readonly Lazy<TRefitService> userInitiated;
private readonly Lazy<TRefitService> speculative;
private ApiService(){}
public ApiService(string baseUrl)
{
ParameterGuard.ThrowIfNullOrEmpty(baseUrl, nameof(baseUrl));
Func<string, RateLimitedHttpMessageHandler, TRefitService> createClient = (address, handler) =>
{
HttpClient client = new HttpClient(handler) {BaseAddress = new Uri(address)};
return RestService.For<TRefitService>(client);
};
background = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Background)));
speculative = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Speculative)));
userInitiated = new Lazy<TRefitService>(() => createClient(baseUrl, new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.UserInitiated)));
}
/// <summary>
/// Use for network requests that are running in the background.
/// </summary>
public TRefitService Background => background.Value;
/// <summary>
/// Use to fetch data into a cache when a page loads. Expect that these requests will only get so far then give up and start failing.
/// </summary>
public TRefitService Speculative => speculative.Value;
/// <summary>
/// Use for network requests that are fetching data that the user is waiting on *right now*.
/// </summary>
public TRefitService UserInitiated => userInitiated.Value;
}
Xamarin Studio 测试失败
[Test()]
public void PassingInANullBaseUrlThrowsAnException()
{
Assert.Throws<ArgumentNullException>(() => new ApiService<IAuthorisationApi>(null));
}
测试结果
Expected: But was: (Could not load type 'ApiService`1' from assembly '/Users/206474978/Desktop/test/test/test/bin/Debug/xxx.xxx.xxx.dll'.) at NUnit.Framework.Assert.Throws (IResolveConstraint expression, NUnit.Framework.TestDelegate code, System.String message, System.Object[] args) <0x377c1c8 + 0x000e6> in :0
at NUnit.Framework.Assert.That (System.Object actual, IResolveConstraint expression, System.String message, System.Object[] args) <0x377c888 + 0x000bf> in :0 at NUnit.Framework.Assert.Throws (IResolveConstraint expression, NUnit.Framework.TestDelegate code, System.String message, System.Object[] args) <0x377c1c8 + 0x00137> in :0
at NUnit.Framework.Assert.Throws (System.Type expectedExceptionType, NUnit.Framework.TestDelegate code, System.String message, System.Object[] args) <0x377bfc8 + 0x0004f> in :0
at NUnit.Framework.Assert.Throws[T] (NUnit.Framework.TestDelegate code, System.String message, System.Object[] args) <0x377bf58 + 0x00033> in :0 at NUnit.Framework.Assert.Throws[T] (NUnit.Framework.TestDelegate code) <0x377bf08 + 0x0003b> in :0 at test.Test+ApiServiceTest.PassingInANullBaseUrlThrowsAnException () [0x00001] in /Users/206474978/Desktop/test/test/test/Test.cs:37 at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /private/tmp/source-mono-4.2.3/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.3/mcs/class/corlib/System.Reflection/MonoMethod.cs:295
现在这通常不是问题,因为我只会使用整形器,但我正在 Jenkins 之上构建我们的持续集成管道,运行 通过 Xamarin 库中的 nunit 包进行测试,结果在构建报告失败中。
知道这里的问题是什么吗?
更新
好的,按照 SushiHangover 的提示,我使用了最新版本的 NUnit 测试运行器并得到了以下输出。似乎错误是 TypeLoadException 或 BadImageFormatException 但我不确定为什么。我检查了两个项目的输出,都设置为 AnyCPU。
[Test()]
public void PassingInAValidBaseAddressGivesAValidRefitUserInitiatedObject()
{
var api = new ApiService<IAuthorisationApi>(BaseAddress);
Assert.IsNotNull(api.UserInitiated);
}
[Test()]
public async Task PassingInAValidBaseAddressReturnsAValidAccountFromTheBackgroundObject()
{
//Arrange
ApiService<IAuthorisationApi> service = = new ApiService<IAuthorisationApi>(BaseAddress);;
//Act
AuthorisationDto account = await service.Background.GetAuthorisationToken(logonPost, "ireland");
//Assert
Assert.IsTrue(account != null);
}
Invalid type xxx.xxx.Core.Services.Lib.ApiService`1 for instance field xxx.xxx.Core.Tests.ApiServiceTest+c__async0:__0
7) Error : xxx.xxx.Core.Tests.ApiServiceTest.PassingInAValidBaseAddressGivesAValidRefitUserInitiatedObject
System.TypeLoadException : Failure has occurred while loading a type.
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x3083b38 + 0x00093> in <filename unknown>:0
8) Error : xxx.xxx.Core.Tests.ApiServiceTest.PassingInAValidBaseAddressReturnsAValidAccountFromTheBackgroundObject
System.BadImageFormatException : Could not resolve field token 0x040001ae
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x3083b38 + 0x00093> in <filename unknown>:0
更新 2
另一个测试因以下堆栈跟踪而失败,这看起来像是单声道的问题?
System.TypeLoadException : Could not load type 'ApiService`1' from assembly '/Users/206474978/Documents/Development/Projects/BRSMemberApp/UnitTests/BrsGolf.Members.Core.Tests/bin/Debug/Brs.Members.Core.dll'.
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /private/tmp/source-mono-4.2.3/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.3/mcs/class/corlib/System.Reflection/MonoMethod.cs:295
(这与我发布的旧 answer 有关)
安装的 Mono 框架包括相对较旧的 NUnit
版本(2.4.8 版)。该版本中有许多 issues/bugs,范围从不正确的异常捕获到 solution/project 解析问题。
我们为 OS-X 构建(包括 Jenkins CI)所做的是通过 nuget 安装最新的 NUnit 到我们的解决方案根目录,并将该安装用于本地测试构建工件。
类似于:
cd YourSolutionRootDir
nuget install nunit.runners
mono ./NUnit.ConsoleRunner.3.2.0/tools/nunit3-console.exe MyTestProject/bin/debug/except.dll
好的,
这是一个非常讨厌的人。该问题与 Mono 或 NUnit 都没有直接关系。尽管旧版本的 NUnit 导致了其他问题。
感谢@SushiHangover 给我的提示,让我开始解决这个问题。
最初我分解了单元测试以实例化 APIService class 的每个依赖项,这些依赖项最终在 iOS、PCL 上标记了 System.Net.Http dll 的问题和单元测试项目。似乎我正在实施的库之一引用了该库的 v1.5.0.0,导致项目版本不匹配,不正确的引用(.Net、PCL 等)加剧了这种情况。我通过在每个项目 app.config.
中包含一个特定的程序集绑定来解决这个问题 <dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
这解决了大约 80 个失败的单元测试,但仍然有大约 50 个失败。
进一步探索发现 PCL 和单元测试项目中的 Akavache 缓存库版本存在问题,该项目解决了另外 40 个单元测试。
最后,在单元测试项目中 运行ning Telerik 的 JustMock 库出现了一个问题,在测试 PCL 时,部分库似乎不受支持。我解决了这个问题,将 JustMock 换成最小起订量并重构了一些测试。这解决了 Xamarin Studio 剩余的失败单元测试。
然后我 运行 在构建服务器上进行这些测试并获得 80 个通过测试和 87 个未通过 运行。妈的
为了解决这个问题,我将 Xamarin v2.4.8 中的默认测试 运行ner 换成了最新下载的测试,现在所有单元测试都在构建服务器上通过了。
长话短说 当您遇到此类问题时,请检查您的参考资料。