Golf Tracker - Service Layer and Unit Tests
Similar to the last episode where I built some simple unit tests for the CourseRepository, in this episode I'll test the service layer classes.Again like previously I have a choice of whether to use a mocking framework like RhinoMocks, Moq, etc., or simply test against a fake repository. And in this case since I'm testing the service layer which isn't directly connected to the data repositories, I can either test the service layer functionality directly, or do what I call "pass-through" testing, which will test against our existing fake repositories. I will be choosing the latter.
Note: when I'm testing against data from a data source such as SQL Server, I prefer to create fake repositories as much as I can to test against. This way I can really see if my queries are working and if my class structures are working. If I'm building an API type of application, I may choose to mock the tests instead. It all depends on the overall scenario.
What I'll do first is create a new class in the UnitTests project for the Course Service tests.
Here's a look at the early version of the service class unit tests.
01.
using
System;
02.
using
GolfTracker.DataObjects.Interfaces;
03.
using
GolfTracker.Services;
04.
using
GolfTracker.UnitTests.Course_Tests;
05.
using
NUnit.Framework;
06.
using
NUnit.Framework.SyntaxHelpers;
07.
08.
namespace
GolfTracker.UnitTests.Course_Service_Tests
09.
{
10.
[TestFixture]
11.
public
class
CourseServiceTests
12.
{
13.
ICourseRepository GetRepository()
14.
{
15.
return
new
FakeCourseRepository(
new
FakeCourseData().GetCourses());
16.
}
17.
18.
[Test]
19.
public
void
Course_Service_Returns_10_Courses()
20.
{
21.
var service =
new
CourseService();
22.
service.CourseRepository = GetRepository();
23.
24.
var courses = service.GetAll();
25.
26.
Assert.AreEqual(10, courses.Count);
27.
}
28.
29.
[Test]
30.
public
void
Course_Name_For_GetById_Is_Course_5()
31.
{
32.
var service =
new
CourseService();
33.
service.CourseRepository = GetRepository();
34.
35.
var course = service.GetById(
new
Guid(
"ed95e452-4675-4bc1-ba1b-9fce741ae51a"
));
36.
37.
Assert.AreEqual(
"Course 5"
, course.CourseName);
38.
}
39.
}
40.
}
As you can see these are very simple tests, and they should be. Each unit test should be as small as possible and be written just to the point that it passes.
Each method first instantiates a new CourseService() class and then applies the dependency injection with the GetRepository() method. At this point we can call any of the methods of the service class. At first we want to make sure everything is working as it should so the tests will be very simple, but as I build the application they will most likely get more complex.
At first all the tests should fail since at this point there is no CourseService concrete class. This is good. RED, GREEN, REFACTOR. After running the tests, we can create the class.
01.
using
System;
02.
using
System.Collections.Generic;
03.
using
System.Linq;
04.
using
System.Text;
05.
using
GolfTracker.Services.Interfaces;
06.
using
Microsoft.Practices.Unity;
07.
using
GolfTracker.DataObjects.Interfaces;
08.
09.
namespace
GolfTracker.Services
10.
{
11.
public
class
CourseService : ICourseService
12.
{
13.
[Dependency]
14.
public
ICourseRepository CourseRepository {
get
;
set
; }
15.
16.
#region ICRUDService<Course> Members
17.
18.
public
List<GolfTracker.BusinessObjects.Course> GetAll()
19.
{
20.
throw
new
NotImplementedException();
21.
}
22.
23.
public
GolfTracker.BusinessObjects.Course GetById(Guid id)
24.
{
25.
throw
new
NotImplementedException();
26.
}
27.
28.
public
Guid Insert(GolfTracker.BusinessObjects.Course model)
29.
{
30.
throw
new
NotImplementedException();
31.
}
32.
33.
public
Guid Update(GolfTracker.BusinessObjects.Course model)
34.
{
35.
throw
new
NotImplementedException();
36.
}
37.
38.
public
void
Delete(GolfTracker.BusinessObjects.Course model)
39.
{
40.
throw
new
NotImplementedException();
41.
}
42.
43.
#endregion
44.
}
45.
}
This is the default CourseService class with the Dependency Injection property set and the interface members implemented.
Now I can run tests against this class. Needless to say the initial tests will fail since all the methods still contain the NotImplementedException() class. In order to make these tests pass I'll just modify the methods that I need to get working. For the first test it will be the GetAll() method.
1.
public
List<GolfTracker.BusinessObjects.Course> GetAll()
2.
{
3.
return
CourseRepository.GetAll().ToList();
4.
}
Now when I run this test it will pass, as long as the number of records in the fake repository hasn't changed.
For the second test I'll need to modify the GetById() method of the CourseService class.
1.
public
GolfTracker.BusinessObjects.Course GetById(Guid id)
2.
{
3.
return
CourseRepository.GetById(id);
4.
}
At this point when I run all tests, they all turn Green!
Stay tuned and in the next episode I'll move up to the presentation layer and begin setting everything up that I need to make the application work the way I need and also help me generate code using tooling such as T4 templates.