-
Notifications
You must be signed in to change notification settings - Fork 0
Testing
The tests in ServiceStack.WebHost.Endpoints.Tests show good examples of how to create stand-alone integration tests that just use a self-hosted HttpListener AppHost.
If you want to unit test a ServiceStack Service in isolation there are a couple of different approaches you can take. The base Service class itself is just a simple C# class which lets you define and inject dependencies manually or by using the built-in IOC container.
We'll illustrate both approaches using this simple unit test example that tests this simple Service:
// DTOs
public class FindRockstars
{
public int? Aged { get; set; }
public bool? Alive { get; set; }
}
public class GetStatus
{
public string LastName { get; set; }
}
public class RockstarStatus
{
public int Age { get; set; }
public bool Alive { get; set; }
}
public class Rockstar
{
[AutoIncrement]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? Age { get; set; }
}
// Implementation
public class SimpleService : Service
{
public IRockstarRepository RockstarRepository { get; set; }
public List<Rockstar> Get(FindRockstars request)
{
return request.Aged.HasValue
? Db.Select<Rockstar>(q => q.Age == request.Aged.Value)
: Db.Select<Rockstar>();
}
public RockstarStatus Get(GetStatus request)
{
var rockstar = RockstarRepository.GetByLastName(request.LastName);
if (rockstar == null)
throw HttpError.NotFound("'{0}' is not a Rockstar".Fmt(request.LastName));
var status = new RockstarStatus
{
Alive = RockstarRepository.IsAlive(request.LastName)
}.PopulateWith(rockstar); //Populates with matching fields
return status;
}
}This Service provides 2 operations, FindRockstars which makes db queries directly in the service class itself, and GetStatus which uses a repository instead for all its Data access.
If you're accessing Db from directly within your service implementation you're going to want to make use of a real DB given the ADO.NET IDbConnection requires a lot of effort to mock. You can do this in the same way you would register your dependencies in ServiceStack itself, by using the built-in IOC. For a unit test we can do this without an AppHost by just use a new Container in your TestFixtureSetup, e.g:
private Container container;
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
container = new Container();
// Use an Sqlite in-memory DB
container.Register<IDbConnectionFactory>(
new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider));
// Register your own dependencies
container.RegisterAutoWiredAs<RockstarRepository, IRockstarRepository>();
// Register the Service so new instances are autowired with your dependencies
container.RegisterAutoWired<SimpleService>();
// Initialize the test state
using (var db = container.Resolve<IDbConnectionFactory>().Open())
{
db.DropAndCreateTable<Rockstar>();
db.InsertAll(SeedData);
}
}With everything setup we can now test the service just like a normal C# class in isolation independently of ServiceStack itself:
[Test]
public void Using_in_memory_database()
{
var service = container.Resolve<SimpleService>(); // Resolve auto-wired service from the IOC
service.SetResolver(new BasicResolver(container)); // Tell Service where to resolve its base class dependencies
var rockstars = service.Get(new FindRockstars { Aged = 27 });
rockstars.PrintDump(); //Print a dumpe of the results to Console
Assert.That(rockstars.Count, Is.EqualTo(SeedData.Count(x => x.Age == 27)));
var status = service.Get(new GetStatus { LastName = "Vedder" });
Assert.That(status.Age, Is.EqualTo(48));
Assert.That(status.Alive, Is.True);
status = service.Get(new GetStatus { LastName = "Hendrix" });
Assert.That(status.Age, Is.EqualTo(27));
Assert.That(status.Alive, Is.False);
Assert.Throws<HttpError>(() =>
service.Get(new GetStatus { LastName = "Unknown" }));
}If you make use of base class dependencies and you're not using an AppHost you'll need to tell the Service where it should look to resolve its base class dependencies by specifying a custom IResolver.
If you prefer your unit tests not to use an in-memory database, you can instead choose to mock your dependencies. In this example we'll use a stand-alone Mock, but you can reduce boilerplate by using mocking library like Moq instead.
public class RockstarRepositoryMock : IRockstarRepository
{
public Rockstar GetByLastName(string lastName)
{
return lastName == "Vedder"
? new Rockstar(6, "Eddie", "Vedder", 48)
: null;
}
public bool IsAlive(string lastName)
{
return lastName == "Grohl" || lastName == "Vedder";
}
}
[Test]
public void Using_manual_dependency_injection()
{
var service = new SimpleService
{
RockstarRepository = new RockstarRepositoryMock()
};
var status = service.Get(new GetStatus { LastName = "Vedder" });
Assert.That(status.Age, Is.EqualTo(48));
Assert.That(status.Alive, Is.True);
Assert.Throws<HttpError>(() =>
service.Get(new GetStatus { LastName = "Hendrix" }));
}
```csharp
This example doesn't need a container as we're injecting all the dependencies manually.
# Community Resources
- [ServiceStack and RavenDB End to End Testing](http://tech.pro/tutorial/1276/servicestack-and-ravendb-end-to-end-testing) by [@aquabirdconsult](https://twitter.com/AquaBirdConsult)
- [Integration Testing With ServiceStack](http://rossipedia.com/blog/2013/02/integration-testing-with-servicestack/) by [@rossipedia](https://twitter.com/rossipedia)
- [How to unit test your database code when using ServiceStack OrmLite](http://www.rickardnilsson.net/post/2013/01/19/how-to-unit-test-your-database-code-when-using-servicestack-ormlite.aspx) by [@rickardn](https://twitter.com/rickardn)
- [EasyHttp and ServiceStack, making the mspec tests better](http://blogs.lessthandot.com/index.php/DesktopDev/MSTech/easyhttp-and-servicestack-making-it) by [@chrissie1](https://twitter.com/chrissie1)
- [Using ServiceStack for the EasyHttp integration tests](http://blogs.lessthandot.com/index.php/DesktopDev/MSTech/using-servicestack-for-the-easyhttp) by [@chrissie1](https://twitter.com/chrissie1)
- [Parameterized Tests for ServiceStack Web Services](http://nikosbaxevanis.com/2012/02/18/parameterized-tests-for-servicestack-web-services/)
### Stack Overflow
- [Unit Test HTTPRequest Headers with ServiceStack](http://stackoverflow.com/a/14791657/85785)
- [Service stack and Mocking, any tutorials?](http://stackoverflow.com/a/9587745/85785)
- [How do you mock ServiceStack ISession using Moq and StructureMap?](http://stackoverflow.com/a/15012300/85785)- Why ServiceStack?
- What is a message based web service?
- Advantages of message based web services
- Why remote services should use separate DTOs
- Getting Started
- Reference
- Clients
- Formats
- View Engines 4. Razor & Markdown Razor
- Hosts
- Security
- Advanced
- Configuration options
- Access HTTP specific features in services
- Logging
- Serialization/deserialization
- Request/response filters
- Filter attributes
- Concurrency Model
- Built-in caching options
- Built-in profiling
- Form Hijacking Prevention
- Auto-Mapping
- HTTP Utils
- Virtual File System
- Config API
- Physical Project Structure
- Modularizing Services
- MVC Integration
- Plugins 3. Request logger 4. Swagger API
- Tests
- Other Languages
- Use Cases
- Performance
- How To
- Future