我已经在ServiceStack 3.9上构建了一个项目,并且使用ServiceStack的自托管API工具进行了广泛的测试覆盖。
我的很多测试装置看起来像这样:
private const string URL_BASE = "http://localhost:60666/";
[TestFixtureSetUp]
public void TestFixtureSetUp() {
AppHost = new HttpTestableAppHost(FakeServices.Register);
AppHost.Init();
AppHost.Start(URL_BASE);
}
[TestFixtureTearDown]
public void TestFixtureTearDown() {
AppHost.Dispose();
AppHost = null;
}
问题在于,如果测试失败,TearDown似乎总是干净利落地运行 - 然后项目上的每个其他测试都会失败并出现相同的错误
System.IO.InvalidDataException:已设置HttpListenerBase.Instance
或不太常见
无法侦听前缀
http://localhost:60666/
,因为它与计算机上的现有注册冲突
当发生这种情况时,整个测试套件将在几分钟内无法运行 - 可能是因为某些基础网络绑定超时或被处置? - 几分钟后,它们全部重新开始工作。
如何更优雅地处理这个问题?有没有什么方法可以在初始化我的AppHost之前强行处理/取消注册http://localhost:60666/
端点,所以在开始新的主机之前它会杀死任何现有的服务主机?当一个人适当的时候,弄清楚正在发生什么事情变得越来越困难。测试失败导致1000多次测试失败,因为其他测试无法初始化他们的HTTP侦听器。
答案 0 :(得分:3)
干净地重新启动ServiceStack主机的唯一方法是卸载它运行的应用程序域并在新的应用程序域中启动一个新实例。
您的问题是related to this question & answer。
示例AppHost
,它将名为MyTest
的对象注册到IoC容器。
public class AppHost : AppSelfHostBase
{
public AppHost(): base("My ServiceStack Service", typeof(AppHost).Assembly)
{
}
public override void Configure(Funq.Container container)
{
container.Register<MyTest>(c => new MyTest());
}
}
public class MyTest
{
public string Name { get { return "Hello"; } }
}
IsolatedAppHost
类: IsolatedAppHost
类用于启动应用程序主机,该主机将在隔离的AppDomain中运行。您可以在此处启动和配置所需的AppHost
,例如HttpTestableAppHost
。
public class IsolatedAppHost : MarshalByRefObject
{
readonly AppHost Host;
public IsolatedAppHost()
{
// Start your HttpTestableAppHost here
Host = new AppHost();
Host.Init();
Host.Start("http://*:8090/");
Console.WriteLine("ServiceStack is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);
}
public void RunTest(Action<AppHost> test)
{
test.Invoke(Host);
}
public void Teardown()
{
if(Host != null)
{
Console.WriteLine("Shutting down ServiceStack host");
if(Host.HasStarted)
Host.Stop();
Host.Dispose();
}
}
}
TestFixture
:您的TestFixureSetup
方法需要在新IsolatedAppHost
中创建AppDomain
的实例。 TestFixtureTearDown
将确保AppHost
和域名正确关闭。
[TestFixture]
public class Test
{
AppDomain ServiceStackAppDomain;
IsolatedAppHost IsolatedAppHost;
[TestFixtureSetUp]
public void TestFixtureSetup()
{
// Get the assembly of our host
var assemblyName = typeof(IsolatedAppHost).Assembly.GetName();
// Create new AppDomain
ServiceStackAppDomain = AppDomain.CreateDomain("ServiceStackAppDomain");
// Load our assembly
ServiceStackAppDomain.Load(assemblyName);
// Create instance
var handle = ServiceStackAppDomain.CreateInstance(assemblyName.FullName, "MyApp.Tests.IsolatedAppHost");
// Unwrap so we can access methods
IsolatedAppHost = (IsolatedAppHost)handle.Unwrap();
}
[TestFixtureTearDown]
public void TestFixtureTearDown()
{
// Tell ServiceStack to stop the host
IsolatedAppHost.Teardown();
// Shutdown the ServiceStack application
AppDomain.Unload(ServiceStackAppDomain);
ServiceStackAppDomain = null;
}
// Tests go here
}
由于测试运动员AppDomain
和AppHost
AppDomain
现在不同,我们无法直接从我们的测试中访问AppHost
。因此,我们将测试传递给RunTest
的{{1}}方法实例。
IsolatedAppHost
例如:
IsolatedAppHost.RunTest(appHost => {
// Your test goes here
});
full source code is here。我希望有所帮助。