Dan*_*sen 1 resharper testdriven.net mspec
我在另一个问题上写过这个话题.
但是,我已经重构了我的代码以摆脱配置访问,从而允许规范通过.或者我想.它们使用TestDriven.Net在Visual Studio中运行良好.但是,当我使用mspec.exe工具在rake中运行它们时,它们仍会因序列化异常而失败.所以我创建了一个完全自包含的示例,除了在线程上设置虚假安全凭证之外基本上什么也没做.这个测试在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; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
担,
感谢您提供复制品.
首先,控制台运行程序的工作方式与TestDriven.NET和ReSharper运行程序不同.基本上,控制台运行器必须执行更多的设置工作,因为它为每个运行的程序集创建一个新的AppDomain(加配置).这是加载规范程序集的.dll.config文件所必需的.
根据规范程序集,创建了两个AppDomain:
Console执行mspec.exe时隐式创建第一个AppDomain(),Spec)的程序集创建第二个AppDomain .两个AppDomain都通过.NET Remoting相互通信:例如,当在SpecAppDomain中执行规范时,它会通知ConsoleAppDomain该事实.当Console收到通知时,它通过将规范信息写入控制台来相应地起作用.
之间的communiciation Spec并Console通过.NET远程透明地实现..NET Remoting的一个属性是,Spec在向目标AppDomain(Console)发送通知时,会自动包含调用AppDomain()的某些属性.Thread.CurrentPrincipal是这样的财产.你可以在这里阅读更多相关信息:http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
您提供的上下文将在SpecAppDomain中运行.你设置Thread.CurrentPrincipal了Because.后Because跑,通知将被发布到ConsoleAppDomain中.该通知将包括您的自定义MyPrincipal接收ConsoleAppDomain尝试反序列化.它不能这样做,因为它不知道您的规范程序集(因为它不包含在其私有bin路径中).
这就是您必须将规范程序集放在与mspec.exe相同的文件夹中的原因.
有两种可能的解决方法:
MyPrincipal并MyIdentity从MarshalByRefObject以使它们可以通过代理采取交叉的AppDomain通信部(而不是被串行化)Thread.CurrentPrincipal暂时设置在Because(格式化工作需要文本 - 请忽略)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
Run Code Online (Sandbox Code Playgroud)
例如,ReSharper为我们处理所有的沟通工作.MSpec的ReSharper Runner可以挂钩到现有的基础架构(即AFAIK,不使用.NET Remoting).
| 归档时间: |
|
| 查看次数: |
803 次 |
| 最近记录: |