Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/debugging/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Resharper 当由mspec.exe运行时,Spec失败,但当由TD.NET运行时,Spec通过_Resharper_Mspec_Testdriven.net - Fatal编程技术网

Resharper 当由mspec.exe运行时,Spec失败,但当由TD.NET运行时,Spec通过

Resharper 当由mspec.exe运行时,Spec失败,但当由TD.NET运行时,Spec通过,resharper,mspec,testdriven.net,Resharper,Mspec,Testdriven.net,我写过这个话题 然而,我已经重构了我的代码,以摆脱配置访问,从而允许规范通过。至少我是这么想的。它们在VisualStudio中使用TestDriven.Net运行良好。但是,当我在rake期间使用mspec.exe工具运行它们时,它们仍然会失败,并出现序列化异常。因此,我创建了一个完全独立的示例,除了在线程上设置假安全凭据外,它基本上什么都不做。这个测试在TD.Net中通过得很好,但在mspec.exe中失败了。有人有什么建议吗 更新:我发现了一个解决方法。在研究该问题后,似乎原因是包含我的主

我写过这个话题

然而,我已经重构了我的代码,以摆脱配置访问,从而允许规范通过。至少我是这么想的。它们在VisualStudio中使用TestDriven.Net运行良好。但是,当我在rake期间使用mspec.exe工具运行它们时,它们仍然会失败,并出现序列化异常。因此,我创建了一个完全独立的示例,除了在线程上设置假安全凭据外,它基本上什么都不做。这个测试在TD.Net中通过得很好,但在mspec.exe中失败了。有人有什么建议吗

更新:我发现了一个解决方法。在研究该问题后,似乎原因是包含我的主要对象的程序集与mspec.exe不在同一文件夹中。当mspec创建一个新的AppDomain来运行我的规范时,这个新的AppDomain必须加载带有主体对象的程序集才能反序列化它。该程序集与mspec EXE不在同一文件夹中,因此失败。如果我将程序集复制到与mspec相同的文件夹中,它就可以正常工作

我仍然不明白的是,为什么ReSharper和TD.Net可以很好地运行测试?他们不使用mspec.exe来实际运行测试吗

using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;

namespace MSpecTest
{
    [Subject(typeof(MyViewModel))]
    public class When_security_credentials_are_faked 
    {
        static MyViewModel SUT;

        Establish context = SetupFakeSecurityCredentials;

        Because of = () =>
            SUT = new MyViewModel();

        It should_be_initialized = () =>
            SUT.Initialized.ShouldBeTrue();

        static void SetupFakeSecurityCredentials()
        {
            Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
        }

        static MyIdentity CreateIdentity()
        {
            return new MyIdentity(Environment.UserName, "None", true);
        }

        static MyPrincipal CreatePrincipal(MyIdentity identity)
        {
            return new MyPrincipal(identity);
        }
    }

    public class MyViewModel
    {
        public MyViewModel()
        {
            Initialized = true;
        }

        public bool Initialized { get; set; }
    }

    [Serializable]
    public class MyPrincipal : IPrincipal
    {
        private readonly MyIdentity _identity;

        public MyPrincipal(MyIdentity identity)
        {
            _identity = identity;
        }

        public bool IsInRole(string role)
        {
            return true;
        }

        public IIdentity Identity
        {
            get { return _identity; }
        }
    }

    [Serializable]
    public class MyIdentity : IIdentity
    {
        private readonly string _name;
        private readonly string _authenticationType;
        private readonly bool _isAuthenticated;

        public MyIdentity(string name, string authenticationType, bool isAuthenticated)
        {
            _name = name;
            _isAuthenticated = isAuthenticated;
            _authenticationType = authenticationType;
        }

        public string Name
        {
            get { return _name; }
        }

        public string AuthenticationType
        {
            get { return _authenticationType; }
        }

        public bool IsAuthenticated
        {
            get { return _isAuthenticated; }
        }
    }
}

谢谢你提供复制品

首先,控制台运行程序的工作方式不同于TestDriven.NET和ReSharper运行程序。基本上,控制台运行程序必须执行更多的设置工作,因为它为运行的每个程序集创建一个新的AppDomain plus配置。这是加载等级库程序集的.dll.config文件所必需的

根据等级库程序集,将创建两个AppDomain:

创建第一个AppDomain控制台 当mspec.exe为 执行, mspec.exe为包含规范的程序集创建第二个AppDomain。 两个AppDomain都通过.NET远程处理相互通信:例如,当在spec AppDomain中执行spec时,它会将该事实通知控制台AppDomain。当控制台收到通知时,它会相应地将规范信息写入控制台

规范和控制台之间的这种通信是通过.NET远程处理透明地实现的。.NET远程处理的一个属性是,在向目标AppDomain控制台发送通知时,会自动包含调用AppDomain规范的某些属性。Thread.CurrentPrincipal就是这样一个属性。您可以在此处阅读更多有关内容:

您提供的上下文将在Spec AppDomain中运行。您在中设置了Thread.CurrentPrincipal,因为。因为运行后,将向控制台AppDomain发出通知。通知将包括接收控制台AppDomain尝试反序列化的自定义MyPrincipal。它不能这样做,因为它不知道您的等级库程序集,因为它不包含在它的文件中

这就是为什么必须将等级库程序集与mspec.exe放在同一文件夹中的原因

有两种可能的解决办法:

从MarshalByRefObject派生MyPrincipal和MyIdentity,以便它们可以通过代理参与跨AppDomain通信,而不是序列化 在中临时设置Thread.CurrentPrincipal,因为 格式设置需要文本-请忽略

Because of = () => 
{
    var previousPrincipal = Thread.CurrentPrincipal;
    try
    {
        Thread.CurrentPrincipal = new MyPrincipal(...);
        SUT = new MyViewModel();
    }
    finally
    {
        Thread.CurrentPrincipal = previousPrincipal;
    }
}
例如,ReSharper为我们处理所有的通信工作。MSpec的ReSharper Runner可以连接到现有的基础设施,而这些基础设施至少不使用.NET远程处理

谢谢你提供复制品

首先,控制台运行程序的工作方式不同于TestDriven.NET和ReSharper运行程序。基本上,控制台运行程序必须执行更多的设置工作,因为它为运行的每个程序集创建一个新的AppDomain plus配置。这是加载等级库程序集的.dll.config文件所必需的

根据等级库程序集,将创建两个AppDomain:

创建第一个AppDomain控制台 当mspec.exe为 执行, mspec.exe为包含规范的程序集创建第二个AppDomain。 两个AppDomain都通过.NET远程处理相互通信:例如,当在spec AppDomain中执行spec时,它会将该事实通知控制台AppDomain。当控制台收到通知时,它会相应地将规范信息写入控制台

规范和控制台之间的这种通信是通过.NET远程处理透明地实现的。.NET远程处理的一个属性是,在向目标AppDomain控制台发送通知时,会自动包含调用AppDomain规范的某些属性。Thread.CurrentPrincipal就是这样一个属性。您可以在此处阅读更多有关内容:

您提供的上下文将在Spec AppDomain中运行。您在中设置了Thread.CurrentPrincipal,因为。因为运行后,将向控制台AppDomain发出通知。通知将包括您的自定义MyPrincipal,即 iving控制台AppDomain尝试反序列化。它不能这样做,因为它不知道您的等级库程序集,因为它不包含在它的文件中

这就是为什么必须将等级库程序集与mspec.exe放在同一文件夹中的原因

有两种可能的解决办法:

从MarshalByRefObject派生MyPrincipal和MyIdentity,以便它们可以通过代理参与跨AppDomain通信,而不是序列化 在中临时设置Thread.CurrentPrincipal,因为 格式设置需要文本-请忽略

Because of = () => 
{
    var previousPrincipal = Thread.CurrentPrincipal;
    try
    {
        Thread.CurrentPrincipal = new MyPrincipal(...);
        SUT = new MyViewModel();
    }
    finally
    {
        Thread.CurrentPrincipal = previousPrincipal;
    }
}
例如,ReSharper为我们处理所有的通信工作。MSpec的ReSharper Runner可以连接到现有的基础设施中,而这些基础设施至少不使用.NET远程处理