所以我试图用RavenDB和ServiceStack构建一个End To End集成测试套件,但是我遇到了一个非常奇怪的问题,验证并没有在某些请求上运行。这真的很奇怪,我不确定我做错了什么。我正在使用NCrunch。有时测试通过,有时它会失败。
希望这是一个简单的解决方案,而且我正在做的事情。
您可以在http://github.com/khalidabuhakmeh/endtoend
下载整个项目除了启用VS2012和NuGet Package Restore之外,您不需要任何其他内容。
更新:我决定在NCrunch和Resharper Test Runner中运行它,两者都给出相同的结果[见下图]。
UPDATE UPDATE:我认为它可能是XUnit,所以我尝试使用NUnit。不是同样的问题。
**另一个更新:根据user1901853的请求输入控制台写入。这就是结果。"
最新更新:RequestFilters正在逐渐消失,我不知道为什么。看起来它可能是一个线程问题,但我无法看到它在哪里。
我的AppHost正在使用AppHostListenerBase。
using EndToEnd.Core;
using Funq;
using Raven.Client;
using ServiceStack.ServiceInterface.Validation;
using ServiceStack.WebHost.Endpoints;
namespace EndToEnd
{
public class TestAppHost
: AppHostHttpListenerBase
{
private readonly IDocumentStore _documentStore;
public TestAppHost(IDocumentStore documentStore)
: base("Test AppHost Api", typeof(TestAppHost).Assembly)
{
_documentStore = documentStore;
}
public override void Configure(Container container)
{
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
// Register RavenDB things
container.Register(_documentStore);
container.Register(c =>
{
var db = c.Resolve<IDocumentStore>();
return db.OpenSession();
}).ReusedWithin(ReuseScope.Request);
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(CreateWidgetValidator).Assembly);
// todo: register all of your plugins here
AuthConfig.Start(this, container);
}
}
}
我所有测试的基础测试类看起来像这样:
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using ServiceStack.Authentication.RavenDb;
using ServiceStack.ServiceClient.Web;
using ServiceStack.ServiceInterface.Auth;
namespace EndToEnd
{
public abstract class ServiceStackTestBase
: RavenTestBase
{
protected IDocumentStore DocumentStore { get; set; }
protected TestAppHost Host { get; set; }
protected JsonServiceClient Client { get; set; }
protected const string ListeningOn = "http://localhost:1337/";
protected string Username { get { return "testuser"; } }
protected string Password { get { return "password"; } }
protected ServiceStackTestBase()
{
DocumentStore = NewDocumentStore();
IndexCreation.CreateIndexes(typeof(ServiceStackTestBase).Assembly, DocumentStore);
IndexCreation.CreateIndexes(typeof(RavenUserAuthRepository).Assembly, DocumentStore);
Host = new TestAppHost(DocumentStore);
Host.Init();
Host.Start(ListeningOn);
Client = new JsonServiceClient(ListeningOn)
{
AlwaysSendBasicAuthHeader = true,
UserName = Username,
Password = Password
};
RegisterUser();
WaitForIndexing(DocumentStore);
}
private void RegisterUser()
{
Client.Send(new Registration
{
UserName = Username,
Password = Password,
DisplayName = "Test User",
Email = "test@test.com",
FirstName = "test",
LastName = "user"
});
}
public override void Dispose()
{
DocumentStore.Dispose();
Host.Dispose();
}
}
}
我的测试类看起来像这样:
using System;
using EndToEnd.Core;
using FluentAssertions;
using ServiceStack.FluentValidation;
using ServiceStack.ServiceClient.Web;
using ServiceStack.ServiceInterface.Auth;
using Xunit;
namespace EndToEnd
{
public class RegistrationTests
: ServiceStackTestBase
{
[Fact]
public void Throws_validation_exception_when_bad_widget()
{
var validator = Host.Container.Resolve<IValidator<CreateWidget>>();
validator.Should().NotBeNull();
try
{
var response = Client.Post(new CreateWidget
{
Name = null
});
// It get's here every once in a while
throw new Exception("Should Not Get Here!");
}
catch (WebServiceException wex)
{
wex.StatusCode.Should().Be(400);
wex.ErrorMessage.Should().Be("'Name' should not be empty.");
}
}
}
}
我的代码对于服务看起来像这样:
using System;
using Raven.Client;
using ServiceStack.FluentValidation;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.ServiceModel;
namespace EndToEnd.Core
{
[Authenticate]
public class WidgetsService
: Service
{
private readonly IDocumentSession _session;
public WidgetsService(IDocumentSession session)
{
_session = session;
}
public CreateWidgetResponse Post(CreateWidget input)
{
var widget = new Widget { Name = input.Name };
_session.Store(widget);
_session.SaveChanges();
return new CreateWidgetResponse { Widget = widget };
}
}
[Route("/widgets", "POST")]
public class CreateWidget : IReturn<CreateWidgetResponse>
{
public string Name { get; set; }
}
public class CreateWidgetResponse
{
public CreateWidgetResponse()
{
ResponseStatus = new ResponseStatus();
}
public Widget Widget { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public class Widget
{
public Widget()
{
Created = DateTimeOffset.UtcNow;
}
public string Id { get; set; }
public string Name { get; set; }
public DateTimeOffset Created { get; set; }
}
public class CreateWidgetValidator : AbstractValidator<CreateWidget>
{
public CreateWidgetValidator()
{
RuleFor(m => m.Name).NotEmpty();
}
}
}
答案 0 :(得分:6)
我无法复制您的环境,但在VS2010中运行时,使用.NET 4,NUnit和ReSharper Test Runner我无法重现您的“验证未触发”问题。我已经运行了30多次测试。我可以想到的几个原因,即验证没有触发,不会添加插件或插件没有注册验证过滤器。如果我列出的任何一个案例都是问题,那么下面的if statements
可能会给你一些“内省”。希望这有点帮助。
if (!TestAppHost.Instance.Plugins.Any(x => x.GetType() == typeof(ValidationFeature)))
{
Console.Write("Validation Plugin is not added");
//TestAppHost.Instance.Plugins.Add(new ValidationFeature());
}
if (!TestAppHost.Instance.RequestFilters.Any(x => x.Target.ToString() == "ServiceStack.ServiceInterface.Validation.ValidationFilters"))
{
Console.Write("No validation request filter");
//TestAppHost.Instance.Container.RegisterValidators(typeof(CreateWidgetValidator).Assembly);
}
下面是我的packages.config,因此您可以看到我们环境中的差异。
<packages>
<package id="FluentAssertions" version="2.0.1" targetFramework="net40" />
<package id="NUnit" version="2.6.2" targetFramework="net40" />
<package id="RavenDB.Client" version="2.0.2261" targetFramework="net40" />
<package id="RavenDB.Database" version="2.0.2261" targetFramework="net40" />
<package id="RavenDB.Embedded" version="2.0.2261" targetFramework="net40" />
<package id="RavenDB.Tests.Helpers" version="2.0.2261" targetFramework="net40" />
<package id="ServiceStack" version="3.9.38" targetFramework="net40-Client" />
<package id="ServiceStack.Authentication.RavenDB" version="3.9.35" targetFramework="net40" />
<package id="ServiceStack.Common" version="3.9.38" targetFramework="net40-Client" />
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.39" targetFramework="net40-Client" />
<package id="ServiceStack.Redis" version="3.9.38" targetFramework="net40-Client" />
<package id="ServiceStack.Text" version="3.9.38" targetFramework="net40-Client" />
<package id="xunit" version="1.9.1" targetFramework="net40" />
</packages>