c# - MSpec Json.NET反序列化测试在ReSharper中失败,但在NCrunch中通过

标签 c# json.net resharper mspec ncrunch

我有以下两个单元测试:一个使用MSTest,另一个使用机器规格。据我所知,它们的行为应相同。但是,虽然第一个通过了NCrunch和ReSharper测试运行程序,但第二个却没有通过ReSharper。

using Machine.Specifications;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;

public class TestModel
{
    public string Name { get; set; }
    public int Number { get; set; }
}

// MSTest
[TestClass]
public class DeserializationTest
{
    [TestMethod]
    public void Deserialized_object_is_the_same_type_as_the_original()
    {
        TestModel testModel = new TestModel() {Name = "John", Number = 42};
        string serialized = JsonConvert.SerializeObject(testModel, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });

        object deserialized = JsonConvert.DeserializeObject(serialized, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });

        // This passes in both test runners
        Assert.IsInstanceOfType(deserialized, typeof(TestModel));
    }
}

// MSpec
public class When_an_object_is_deserialized
{
    static TestModel testModel;
    static string serialized;
    static object deserialized;

    Establish context = () =>
    {
        testModel = new TestModel() { Name = "John", Number = 42 };
        serialized = JsonConvert.SerializeObject(testModel, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });
    };

    Because of = () => deserialized = JsonConvert.DeserializeObject(serialized, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });

    // This passes in NCrunch but fails in ReSharper.
    It should_be_the_same_type_as_the_original = () => Assert.IsInstanceOfType(deserialized, typeof(TestModel));
}


失败消息是:Assert.IsInstanceOfType failed. Expected type:<UnitTestProject2.TestModel>. Actual type:<UnitTestProject2.TestModel>.奇怪的是,以下内容确实通过了:

It should_be_the_same_type_as_the_original = () => Assert.IsTrue(testModel.GetType() == typeof(TestModel));


我正在以这种方式进行反序列化,因为有问题的实际代码需要能够处理类型,直到运行时才知道的对象。我认为Json.NET进行这种反序列化的方式有些奇怪,但是为什么两个测试运行者的行为会有所不同?我在Visual Studio 2013中使用ReSharper 9.1。

最佳答案

显然,由于NCrunch和ReSharper之间的行为存在细微差别,因此会产生奇怪的运行时效果。失败肯定是在告诉您出了点问题,您不应该将其视为ReSharper或NCrunch中的错误。

当我在调试器中逐步执行MSpec测试时,deserialized对象在调试器中显示以下错误:


deserialized  Cannot fetch the value of field 'deserialized' because information about the containing class is unavailable.   object



很难确定没有完整的解决方案,但是当构建输出目录包含一个程序集的多个副本(可能在子目录中)时,我已经看到了这种情况。如果不同的零件在不同的时间引用了程序集的不同副本,则有时即使该程序集的类型实际上是该程序集的相同副本,也不会将其类型视为相等。解决方案是确保构建输出中每个程序集只有一个副本,以确保所有内容都引用完全相同的文件。可能是JSON转换器正在动态加载您的类型并获取错误的程序集,或者可能将其加载到其他加载上下文中,这意味着它的类型与在其他上下文中加载的副本不相等。

在MSpec案例中,可能与您的构建环境有关,从而导致程序集的重复副本。特别是NCruch,默认情况下不执行构建后事件(通常会显示警告),因此,如果在构建后步骤中复制文件,则可能是不同行为的一种解释。您可以通过在NCrunch中启用生成后事件并查看是否发生故障来进行检查。

另一个可能的疑难解答步骤是使用Fusion Log Viewer(fuslogvw.exe)记录程序集绑定,您应该能够准确计算出正在加载的程序集以及在什么加载上下文中。

更新
我很确定这是由JSON转换器在运行时使用程序集引起的程序集绑定问题。在融合日志中,我找到了以下条目:

*** Assembly Binder日志条目(05/06/2015 @ 02:01:38)***

操作成功。
绑定结果:hr = 0x0。操作成功完成。

程序集管理器从以下位置加载:C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ clr.dll
在可执行文件C:\ Users \ Tim \ AppData \ Local \ JetBrains \ Installations \ ReSharperPlatformVs12_001 \ JetBrains.ReSharper.TaskRunner.CLR45.x64.exe下运行
---详细的错误日志如下。

日志:IJW显式绑定。文件路径:c:\ users \ tim \ VS-Projects \ StackOverflow \ StackOverflow.30643046 \ bin \ Debug \ StackOverflow.30643046.dll。
日志:IJW程序集绑定返回了另一个路径:C:\ Users \ Tim \ AppData \ Local \ Temp \ k3dpwn5u.uii \ Machine Specification Runner \ assembly \ dl3 \ 6c41c492 \ c7eea8ec_279fd001 \ StackOverflow.30643046.dll。使用提供的文件。


我也发现了这个:

*** Assembly Binder日志条目(05/06/2015 @ 02:01:38)***

操作成功。
绑定结果:hr = 0x0。操作成功完成。

程序集管理器从以下位置加载:C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ clr.dll
在可执行文件C:\ Users \ Tim \ AppData \ Local \ JetBrains \ Installations \ ReSharperPlatformVs12_001 \ JetBrains.ReSharper.TaskRunner.CLR45.x64.exe下运行
---详细的错误日志如下。

WRN:同一程序集已加载到应用程序域的多个上下文中:
WRN:上下文:默认|域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:上下文:都不域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:这可能会导致运行时失败。
WRN:建议检查您的应用程序是否故意。
WRN:有关此问题的更多信息和常见解决方案,请参见白皮书http://go.microsoft.com/fwlink/?LinkId=109270。


*** Assembly Binder日志条目(05/06/2015 @ 02:04:41)***

操作成功。
绑定结果:hr = 0x0。操作成功完成。

程序集管理器从以下位置加载:C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ clr.dll
在可执行文件C:\ Users \ Tim \ AppData \ Local \ JetBrains \ Installations \ ReSharperPlatformVs12_001 \ JetBrains.ReSharper.TaskRunner.CLR45.x64.exe下运行
---详细的错误日志如下。

WRN:同一程序集已加载到应用程序域的多个上下文中:
WRN:上下文:默认|域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:上下文:都不域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:这可能会导致运行时失败。
WRN:建议检查您的应用程序是否故意。
WRN:有关此问题的更多信息和常见解决方案,请参见白皮书http://go.microsoft.com/fwlink/?LinkId=109270。


***装订夹日志输入(05/06/2015 @ 02:04:42)***

操作成功。
绑定结果:hr = 0x0。操作成功完成。

程序集管理器从以下位置加载:C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ clr.dll
在可执行文件C:\ Users \ Tim \ AppData \ Local \ JetBrains \ Installations \ ReSharperPlatformVs12_001 \ JetBrains.ReSharper.TaskRunner.CLR45.x64.exe下运行
---详细的错误日志如下。

WRN:同一程序集已加载到应用程序域的多个上下文中:
WRN:上下文:默认|域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:上下文:都不域ID:2 |程序集名称:StackOverflow.30643046,版本= 1.0.0.0,文化=中性,PublicKeyToken =空
WRN:这可能会导致运行时失败。
WRN:建议检查您的应用程序是否故意。
WRN:有关此问题的更多信息和常见解决方案,请参见白皮书http://go.microsoft.com/fwlink/?LinkId=109270。


我还发现,禁用ReSharper单元测试选项“正在测试的卷影副本程序集”会导致测试通过。

所以我认为我们有“吸烟枪”。由于让JSON反序列化器在运行时发现类型的方式,您的程序集加载有冲突。

更新2015-06-11

我在MSpec邮件列表中注意到this,它可能与您的问题有关:[machine.specifications] Shadow copying broken - creates very subtle bugs in tests

关于c# - MSpec Json.NET反序列化测试在ReSharper中失败,但在NCrunch中通过,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30643046/

相关文章:

c# - System.dll 中的 System.ServiceModel.FaultException

c# - 查找 IEnumerable 的第一个索引

c# - 强制将空 JSON 数组转换为字典类型

javascript - 在 Javascript 中扩展 native Date 对象是否会导致意外效果?

c# - 从 Azure IoT 中心获取设备列表

c# - 有没有一种方法可以调整此功能使其不使用 LINQ? (将字节数组转换为字符串)

c# - 无法加载文件或程序集 'Newtonsoft.Json,版本 = 3.5.0.0

c# - 自定义反序列化器仅适用于 json.NET 的某些字段

c# - Ctrl+R,Ctrl+R 命令不起作用

c# - 如何使用 Resharper CodeAnnotation 属性指示结果不明确?