Regression testing ServiceStack services with RavenDB embeded

One of the great things about using RavenDB and ServiceStack on Sonatribe is the ability to spin the whole system up inside a unit test. ServiceStack offers AppHostHttpListenerBase which can run in process and RavenDB offers the embeded database which can run in-memory. The fact that these two run in-process and in-memory means that regression testing Sonatribe REST services is simple and fast. Almost as fast as unit testing!

To be able to run tests like the following regression test:


[Test]
public async void CanGetAccount()
{
var user = await Client.PostAsync(new PostUserAccountRequest
{
Name = UserName,
Slug = UserName,
Username = UserName,
ThirdPartyUsername = UserName
});
var response = await Client.GetAsync(new GetUserAccountRequest
{
Id = user.Results[0].Id
});
response.Results[0].Id.Should().NotBeNull();
}
view raw gistfile1.cs hosted with ❤ by GitHub


I use the AppHostHttpListenerBase in my BaseTest class. Which is roughly the same as the following:


namespace Sonatribe.Tests.RegressionTests
{
public class SelfHostedBaseTest
{
protected IServiceClient Client;
protected AuthAppHostHttpListener AppHost;
protected virtual string ListeningOn
{
get { return "http://localhost:82/"; }
}
protected virtual string WebHostUrl
{
get { return "http://some.api.sonatribe.com"; }
}
[TestFixtureSetUp]
public void OnTestFixtureSetUp()
{
AppHost = new AuthAppHostHttpListener(WebHostUrl, Configure);
AppHost.Init();
AppHost.Start(ListeningOn);
//other set up stuff
}
[TestFixtureTearDown]
public void OnTestFixtureTearDown()
{
AppHost.Dispose();
}
protected IServiceClient GetClient()
{
return new JsonServiceClient(ListeningOn)
{
UserName = "xxxxx",
Password = "xxxxx"
};
}
public virtual void Configure(Container container)
{
container.Register<IServiceClient>(Client);
}
public class AuthAppHostHttpListener : AppHostHttpListenerBase
{
private readonly string _webHostUrl;
private Action<Container> _configureFn;
public AuthAppHostHttpListener(string webHostUrl, Action<Container> configureFn = null)
: base("Validation Tests", typeof(OneOfYourServices).Assembly)
{
_webHostUrl = webHostUrl;
_configureFn = configureFn;
}
public override void Configure(Funq.Container container)
{
JsConfig.EmitCamelCaseNames = true;
ConfigureAuth(container);
ConfigureContainer(container);
InstallRaven(container);
}
public void InstallRaven(Funq.Container container)
{
var store = new EmbeddableDocumentStore
{
Configuration =
{
RunInUnreliableYetFastModeThatIsNotSuitableForProduction = true,
RunInMemory = true
}
}.Initialize();
//you can switch to a live/deployed API here if that tickles your fancy
//var store = new DocumentStore()
//{
// ConnectionStringName = "SonatribeConnectionString"
//}.Initialize();
store.Conventions.IdentityPartsSeparator = "-";
container.Register<IDocumentStore>(store);
container.Register<IDocumentSession>(c => c.Resolve<IDocumentStore>().OpenSession()).ReusedWithin(ReuseScope.Request);
}
public static void DoInitialisation(IDocumentStore store)
{
store.Initialize();
store.Conventions.IdentityPartsSeparator = "-";
store.Conventions.DefaultQueryingConsistency = ConsistencyOptions.AlwaysWaitForNonStaleResultsAsOfLastWrite;
//install transformers and indexes here
}
private void ConfigureContainer(Container container)
{
container.Register(c => c.Resolve<IDocumentStore>().OpenSession()).ReusedWithin(ReuseScope.Default);
container.Register(c => c.Resolve<IDocumentStore>().OpenAsyncSession()).ReusedWithin(ReuseScope.Default);
//configure the dependancies that are needed by your services here
//this is generally the same set up as your actual service host
}
private void ConfigureAuth(Container container)
{
var appSettings = new AppSettings();
SetConfig(new HostConfig
{
WebHostUrl = _webHostUrl,
StripApplicationVirtualPath = true,
DebugMode = true,
GlobalResponseHeaders =
{
{"Access-Control-Allow-Origin", "*"},
{"Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"},
{"Access-Control-Allow-Headers", "Content-Type"},
}
});
Plugins.Add(new AuthFeature(
() => new CustomUserSession(),
new IAuthProvider[]
{
new CredentialsAuthProvider(),
new TwitterAuthProvider(appSettings),
new FacebookAuthProvider(appSettings),
new DigestAuthProvider(appSettings),
new BasicAuthProvider()
}) { HtmlRedirect = null });
container.Register<IAuthRepository>(
c => new RavenDbUserAuthRepository(container.Resolve<IDocumentStore>()));
}
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

Now, When I inherit from SelfHostedBaseTest each test spins up a new host and a new in-memory RavenDB instance. This means I have a clean slate for each test, ideal for running everything in isolation. Not only this but I am also testing my services in the exact same stack as they run in production!

Comments