Web Service Testing
Unit testing of the Services
Web Services and Cloud
Telerik Software Academy
http://academy.telerik.com
Table of Contents
Ways of web service testing
Unit Testing
Integration Testing
Complete Testing of Web Services
Unit testing the data layer
Unit testing the repositories layer
Unit testing the controllers
Integration testing the web services
Web Service Testing
Web Service Testing
Web service unit testing is much like regular
unit testing
Writing test methods to test methods etc..
Yet a service is
build from many more
components than POCO objects
There are the objects, service routing, media
types, HTTP Status codes, etc…
Web Service Testing (2)
When a web service is ready for test, the
testing itself is performed in the following
steps:
Write Unit Tests to test the C# objects
Test all objects, their constructors, their methods
Write the Integration Testing
Test the application as if a user tests it
Unit Testing
Testing the Work of the Controllers
Unit Testing
The core idea of Unit testing is to test small
components of an application
Test a single behavior (a method, property,
constructor, etc…)
Unit tests cover all C# components of the app
Models and data layer
Like repositories and DB/XML read/write
Business layer
Controllers and their actions
Unit Testing the Data Layer
Unit Testing the Data Layer
The data layer is the one thing that most of
the time does not need testing
The idea of the data layer is to reference a data
store with a ready-to-use framework
EntityFramework, NHibernate, OpenAccess
They are already tested enough
No point of testing dbContext.Set<T>.Add(),
right?
Unit Testing the Repositories
Unit Testing the Repositories
It is essential to test the implementations of
our repositories
The repositories contain the data store logic
All custom (developer) logic must be tested
A missing dbContext.SaveChanges() can cause
a lot of pain
Unit Testing the
Repositories (2)
How to test the data store logic?
Writing and deleting the original (production)
database is not quite a good option
Imagine a failed test that leaves 100k test
records in the database
Ways to Unit Test a Data Store
A few ways exist to unit test a data store
Manually create a copy of the data store and
work on the copy
Backup the original data store, work on the
original, and restore the backup when the tests
are over
Use transactions, to prevent commit to the
data store
Unit Testing with Transactions
When testing with transactions,
the changes
done are not really applied to the data store
Whatever commited, if tran.Complete() is
not called, the transaction logic is rolled back
How to use transactions
in unit tests?
Create a static TransactionScope instance
Initialize the transaction in TestInitialize()
Dispose the transaction in TestCleanup()
Unit Testing with
Transactions
Live Demo
How should be tested the
repositories?
What parts
of the repositories should our tests
cover?
Test for correct behavior
Add, Delete, Get, All, etc…
Test for incorrect behavior
Test Add with Category that has NULL name
Unit Testing the
Repositories
Live Demo
Unit Testing the Services
Unit Testing the Services
Testing the services layers
actually means
testing the controllers and the REST API
Test if controllers work correctly as C# objects
Using mocking or fake repositories
Test if the endpoints of the REST services work
correctly
Check the StatusCode and Content
Unit Testing of the Controllers
The Unit testing of the controllers
is not much
of a big deal
Test them as regular C# classes
Instantiate an object, and test its methods
(actions)
The repositories can be mocked/faked for easier
testing
If not mocked, the transaction technique should
be used again
Unit Testing Controllers with
Fake Repositories
To test the controllers, repositories should be
faked
i.e. create a in-memory repository that
implements the IRepository<T> interface
class FakeRepository<T> : IRepository<T> where T:class {
IList<T> entities = new List<T>();
public T Add(T entity) {
this.entities.Add(entity);
return entity;
}
public T Get(int id)
{
return this.entities[id];
}
…
}
Unit Testing Controllers with
Fake Repositories (2)
With the Fake Repository present, controllers can
be tested by passing their constructor a fake rep
public void GetAll_OneCategoryInRepository_ReturnOneCategory()
{
//arrange
var repository = new FakeRepository<Category>();
var categoryToAdd = new Category(){ Name = "Test category" };
repository.Add(categoryToAdd);
var controller = new CategoriesController(repository);
//act
var categoriesModels = controller.GetAll();
//assert
Assert.IsTrue(categoriesModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoriesModels.First().Name);
}
Unit Testing Controllers with
Fake Repositories (2)
With the Fake Repository present, controllers can
be tested by passing their constructor a fake rep
public void GetAll_OneCategoryInRepository_ReturnOneCategory()
{
Prepare the repository
//arrange
var repository = new FakeRepository<Category>();
var categoryToAdd = new Category(){ Name = "Test category" };
repository.Add(categoryToAdd);
var controller = new CategoriesController(repository);
//act
var categoriesModels = controller.GetAll();
//assert
Assert.IsTrue(categoriesModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoriesModels.First().Name);
}
Unit Testing Controllers with
Fake Repositories (2)
With the Fake Repository present, controllers can
be tested by passing their constructor a fake rep
public void GetAll_OneCategoryInRepository_ReturnOneCategory()
{
Prepare the repository
//arrange
var repository = new FakeRepository<Category>();
var categoryToAdd = new Category(){ Name = "Test category" };
repository.Add(categoryToAdd);
var controller = new CategoriesController(repository);
//act
var categoriesModels = controller.GetAll();
Pass it to the controller
//assert
Assert.IsTrue(categoriesModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoriesModels.First().Name);
}
Unit Testing Controllers with
Fake Repositories (2)
With the Fake Repository present, controllers can
be tested by passing their constructor a fake rep
public void GetAll_OneCategoryInRepository_ReturnOneCategory()
{
Prepare the repository
//arrange
var repository = new FakeRepository<Category>();
var categoryToAdd = new Category(){ Name = "Test category" };
repository.Add(categoryToAdd);
var controller = new CategoriesController(repository);
//act
var categoriesModels = controller.GetAll();
Pass it to the controller
//assert
Act on the controller
Assert.IsTrue(categoriesModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoriesModels.First().Name);
}
Unit Testing Controllers with
Fake Repositories (2)
With the Fake Repository present, controllers can
be tested by passing their constructor a fake rep
public void GetAll_OneCategoryInRepository_ReturnOneCategory()
{
Prepare the repository
//arrange
var repository = new FakeRepository<Category>();
var categoryToAdd = new Category(){ Name = "Test category" };
repository.Add(categoryToAdd);
var controller = new CategoriesController(repository);
//act
var categoriesModels = controller.GetAll();
Pass it to the controller
//assert
Act on the controller
Assert.IsTrue(categoriesModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoriesModels.First().Name);
}
Assert the result
Unit Testing with Fake
Repositories
Live Demo
Unit Testing with JustMock
Creating
fake repository for each and every
unit test is kind of boring
Here comes the mocking
Provide objects that mimic some functionality
JustMock/Moq provide mocking functionality
Creates a fake instance of an interface and
implement only the functionality needed
Unit Testing with JustMock (2)
[TestMethod]
public void GetAll_SingleCategoryInRepository_ReturnsTheCategory()
{
//arrange
var repository = Mock.Create<IRepository<Category>>();
var categoryToAdd = GetTestCategory();
IList<Category> entities = new List<Category>(){ categoryToAdd };
Mock.Arrange(() => repository.All())
.Returns(() => entities.AsQueryable());
var controller = new CategoriesController(repository);
//act
var categoryModels = controller.GetAll();
//assert
Assert.IsTrue(categoryModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoryModels.First().Name);
}
Unit Testing with JustMock (2)
[TestMethod]
public void GetAll_SingleCategoryInRepository_ReturnsTheCategory()
{
Create the mock object
//arrange
var repository = Mock.Create<IRepository<Category>>();
var categoryToAdd = GetTestCategory();
IList<Category> entities = new List<Category>(){ categoryToAdd };
Mock.Arrange(() => repository.All())
.Returns(() => entities.AsQueryable());
var controller = new CategoriesController(repository);
//act
var categoryModels = controller.GetAll();
//assert
Assert.IsTrue(categoryModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoryModels.First().Name);
}
Unit Testing with JustMock (2)
[TestMethod]
public void GetAll_SingleCategoryInRepository_ReturnsTheCategory()
{
Create the mock object
//arrange
var repository = Mock.Create<IRepository<Category>>();
var categoryToAdd = GetTestCategory();
Mock the All() behavior
IList<Category> entities = new List<Category>(){
categoryToAdd };
Mock.Arrange(() => repository.All())
.Returns(() => entities.AsQueryable());
var controller = new CategoriesController(repository);
//act
var categoryModels = controller.GetAll();
//assert
Assert.IsTrue(categoryModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoryModels.First().Name);
}
Unit Testing with JustMock (2)
[TestMethod]
public void GetAll_SingleCategoryInRepository_ReturnsTheCategory()
{
Create the mock object
//arrange
var repository = Mock.Create<IRepository<Category>>();
var categoryToAdd = GetTestCategory();
Mock the All() behavior
IList<Category> entities = new List<Category>(){
categoryToAdd };
Mock.Arrange(() => repository.All())
.Returns(() => entities.AsQueryable());
var controller = new CategoriesController(repository);
//act
var categoryModels = controller.GetAll();
Act on the controller
//assert
Assert.IsTrue(categoryModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoryModels.First().Name);
}
Unit Testing with JustMock (2)
[TestMethod]
public void GetAll_SingleCategoryInRepository_ReturnsTheCategory()
{
Create the mock object
//arrange
var repository = Mock.Create<IRepository<Category>>();
var categoryToAdd = GetTestCategory();
Mock the All() behavior
IList<Category> entities = new List<Category>(){
categoryToAdd };
Mock.Arrange(() => repository.All())
.Returns(() => entities.AsQueryable());
var controller = new CategoriesController(repository);
//act
var categoryModels = controller.GetAll();
Act on the controller
//assert
Assert.IsTrue(categoryModels.Count() == 1);
Assert.AreEqual(categoryToAdd.Name,
categoryModels.First().Name);
}
Assert the result
Unit Testing With JustMock
Live Demo
More About Controllers
Unit Testing
GET actions
are easy to test
They return POCO objects
How to test POST actions?
They return HttpResponseMessage
Unfortunately POST actions
require additional
configuration due to the Request object they
use
Configuring POST Actions
A simple POST action:
public HttpResponseMessage Post(CategoryModel model)
{
var entity = this.categoriesRepository.Add(model);
var response = Request.CreateResponse<CategoryModel>(
HttpStatusCode.Created,
entity);
var resourceLink = Url.Link("DefaultApi",
new { id = entity.Id });
response.Headers.Location = new Uri(resourceLink);
return response;
}
Configuring POST Actions
A simple POST action:
public HttpResponseMessage Post(CategoryModel model)
{
var entity = this.categoriesRepository.Add(model);
var response = Request.CreateResponse<CategoryModel>(
HttpStatusCode.Created,
Run in unit test, Request
entity);
has a value of null
var resourceLink
= Url.Link("DefaultApi",
new { id = entity.Id });
response.Headers.Location = new Uri(resourceLink);
return response;
}
If a controller is invoked outside of WebAPI
environment, the Request object is not set
Configuring POST Actions (2)
To have a non-null value of the Request object,
it must be set up manually
private void SetupController(ApiController controller)
{
var request = new HttpRequestMessage()
{ RequestUri = new Uri("http://test-url.com")};
controller.Request = request;
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
controller.Configuration = config;
controller.RequestContext.RouteData = new HttpRouteData(
route: new HttpRoute(),
values: new HttpRouteValueDictionary {
{ "controller", "categories" }
});
}
Configuring POST Actions (2)
To have a non-null value of the Request object,
it must be set up manually
private void SetupController(ApiController controller)
{
Create a Request object
var request = new HttpRequestMessage()
{ RequestUri = new Uri("http://test-url.com")};
controller.Request = request;
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
controller.Configuration = config;
controller.RequestContext.RouteData = new HttpRouteData(
route: new HttpRoute(),
values: new HttpRouteValueDictionary {
{ "controller", "categories" }
});
}
Configuring POST Actions (2)
To have a non-null value of the Request object,
it must be set up manually
private void SetupController(ApiController controller)
{
Create a Request object
var request = new HttpRequestMessage()
{ RequestUri = new Uri("http://test-url.com")};
controller.Request = request;
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
Create a config
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
controller.Configuration = config;
controller.RequestContext.RouteData = new HttpRouteData(
route: new HttpRoute(),
values: new HttpRouteValueDictionary {
{ "controller", "categories" }
});
}
Unit Testing POST Actions
Live Demo
Integration Testing
Integration Testing
Integration testing aims to cover the work of
the whole application
Not small components like unit testing
Integration tests should work like a user
Test what a user sees in combination of all
application components mixed together
Integration Testing WebAPI
When integration testing WebAPI, controllers
and their actions are assumed to be working
correctly
In WebAPI, integration tests should cover:
The endpoints of the RESTful services
Test if the endpoint reaches the correct action
Test the serialization of the data
Does it work with JSON/XML
Is the data serialized correctly
Integration Testing WebAPI (2)
Integration testing a GET request:
[TestMethod]
public void GetAll_SingleCategory_StatusCodeOkAndNotNullContent()
{
var mockRepository = Mock.Create<IRepository<Category>>();
var models = new List<Category>();
models.Add(new Category() { Name = "Test Cat" });
Mock.Arrange(() => mockRepository.All())
.Returns(() => models.AsQueryable());
var server = new InMemoryHttpServer<Category>(
"http://localhost/",
mockRepository);
var response = server.CreateGetRequest("api/categories");
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Content);
}
Integration Testing WebAPI (2)
Integration testing a GET request:
[TestMethod]
public void GetAll_SingleCategory_StatusCodeOkAndNotNullContent()
{
var mockRepository = Mock.Create<IRepository<Category>>();
var models = new List<Category>();
models.Add(new Category() { Name = "Test Cat" });
Fake in-memory server, that
Mock.Arrange(() => mockRepository.All()) hosts the WebAPI controllers
.Returns(() => models.AsQueryable());
var server = new InMemoryHttpServer<Category>(
"http://localhost/",
mockRepository);
var response = server.CreateGetRequest("api/categories");
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Content);
}
Integration Testing
Live Demo
Unit Testing Web Services
курсове и уроци по програмиране, уеб дизайн – безплатно
курсове и уроци по програмиране – Телерик академия
уроци по програмиране и уеб дизайн за ученици
програмиране за деца – безплатни курсове и уроци
безплатен SEO курс - оптимизация за търсачки
курсове и уроци по програмиране, книги – безплатно от Наков
уроци по уеб дизайн, HTML, CSS, JavaScript, Photoshop
free C# book, безплатна книга C#, книга Java, книга C#
безплатен курс "Качествен програмен код"
безплатен курс "Разработка на софтуер в cloud среда"
BG Coder - онлайн състезателна система - online judge
форум програмиране, форум уеб дизайн
ASP.NET курс - уеб програмиране, бази данни, C#, .NET, ASP.NET
ASP.NET MVC курс – HTML, SQL, C#, .NET, ASP.NET MVC
алго академия – състезателно програмиране, състезания
курс мобилни приложения с iPhone, Android, WP7, PhoneGap
Дончо Минков - сайт за програмиране
Николай Костов - блог за програмиране
C# курс, програмиране, безплатно
http://academy.Telerik.com
Homework
Develop a REST API for a BugLogger app
Bugs have status:
fixed, assigned, for-testing, pending
Bugs have text and logDate
Newly added bugs always have status "pending"
Bugs can be queried – get all bugs, get bugs after a date,
get only pending bugs, etc…
1.
Develop a database in MS SQL Server that keeps the
data of the bugs
2.
Create repositories to work with the bugs database
Homework (2)
Provide a REST API to work with the bugs
3.
Using WebAPI
Provide the following actions:
Log new bug
POST …/bugs
Get all bugs
GET …/bugs
Get bugs after a specific date:
Get bugs by status
GET …/bugs?type=pending
Change bug status
PUT …/bugs/{id}
GET …/bugs?date=22-06-2014
Write unit tests to test the BugLogger
4.
5.
Use a mocking framework
Write integration tests to test the BugLogger
© Copyright 2026 Paperzz