It is time to implement all the classes from the preceding class diagram and look at our overall source and project structure.
Let's open Visual Studio and create a blank solution named EmployeeBeneftis.sln
. In this solution, let's add a project of the Class Library type named Domain
.
To add a blank solution, you need to go to File | New | Project. On the New Project dialog that opens, inside the pane on the left side, locate a tree node named Other Project Types. Inside this node, you will find an item named Visual Studio Solutions. Click on this item, and then, you can choose Blank Solution in the middle pane.
We will now add all the classes to the Domain
project. In order to minimize the compilation errors, we will start with the class that does not refer to other classes. Right-click on the Domain
project in Visual Studio and add a class named Address
. Use the following code for the body of the class:
namespace Domain { public class Address { public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } public string Postcode { get; set; } public string City { get; set; } public string Country { get; set; } } }
For the sake of brevity, I am skipping the using namespace
statements from these code snippets. I intend to do so unless the mention of namespace is critical to the piece of code at hand. Other times, you should be able to proceed with whatever namespaces Visual Studio adds for you automatically.
Let's add a second class named Benefit
and use the following code snippet: This class acts as a base class for any class that represents an employee benefit:
namespace Domain { public class Benefit { public string Name { get; set; } public string Description { get; set; } public Employee Employee { get; set; } } }
Next, we can add classes representing our three benefits. Before this, let's define the enumeration that will be used by the leave benefit as follows:
namespace Domain { public enum LeaveType { Casual, Sick, Unpaid } }
With the enumeration in place, here is the code snippet for our three employee benefit classes:
namespace Domain { public class SkillsEnhancementAllowance : Benefit { public int RemainingEntitlement { get; set; } public int Entitlement { get; set; } } } namespace Domain { public class SeasonTicketLoan : Benefit { public int Amount { get; set; } public double MonthlyInstalment { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } } } namespace Domain { public class Leave : Benefit { public LeaveType Type { get; set; } public int AvailableEntitlement { get; set; } public int RemainingEntitlement { get; set; } } }
We have all the classes in place except the class that represents an employee. Let's add one more classes named Employee
and use the following code snippet:
namespace Domain { public class Employee { public string EmployeeNumber { get; set; } public string Firstname { get; set; } public string Lastname { get; set; } public string EmailAddress { get; set; } public DateTime DateOfBirth { get; set; } public DateTime DateOfJoining { get; set; } public Address ResidentialAddress { get; set; } public bool IsAdmin { get; set; } public string Password { get; set; } public ICollection<Benefit> Benefits { get; set; } } }
Note that we have a collection of Benefit
classes in the Employee
class. Not every employee may be eligible for every type of benefit. So, we cannot have an association to every benefit type in Employee
. A collection of benefits helps with such a situation when you do not know in advance which benefits a particular employee is eligible for. Our code should compile at this point. If not, just fix whatever errors come up.
Next, we are going to add one more project for our unit tests. So, let's add another project of the Class Library type and name it Tests.Unit
. This project needs to reference the Domain
project because we will be calling into the classes defined in the Domain
project from our tests. We are going to use NUnit to write our tests. So, let's go and grab NUnit by using NuGet.
There are two ways in which you can add NuGet packages to your projects. The first one uses the Manage NuGet Packages menu of Visual Studio. This is an easy-to-follow option in which you do not need to leave Visual Studio. The second uses the Package Manager Console feature of Visual Studio. This is slightly involved but gives you better control over the packages that you are installing. We will look at the first option here. I will leave the second option for you to explore:
Tests.Unit
. You would see the following menu pop out:Tests.Unit
project. This is how the dialog looks:On this dialog, there is a search box in the top-right corner. We can enter here the names of the packages that we want to search.
In the left-hand pane, you can see various options. I do not intend to go into the details of these, but one thing worth noting is that nuget.org is selected. This means that we are using nuget.org as our source of NuGet packages. If you are using a different source, then you can change this from the settings, but you will rarely need to do so.
Tests.Unit
project. After NUnit is successfully installed, the Manage NuGet Packages dialog changes to look as shown in the following screenshot:Tests.Unit
project.If you have never used NUnit, here is a brief primer for you:
[Test]
is added to a test method. This is how NUnit distinguishes between a test method and a normal method.[TestFixture]
added to it. That is how the NUnit GUI runner (or other NUnit runners) finds all the test classes/fixtures to be run. However, with the latest versions of ReSharper, this attribute is not required.using
statement to reference the NUnit.Framework
namespace should be added to any class that has test methods in it.using NUnit.Framework namespace Tests.Unit { [TestFixture] public class EmployeeTests { [Test] public void EmployeeIsEntitledToPaidLeaves() { //Arrange var employee = new Employee(); //Act employee.Leaves = new List<Leave>(); employee.Leaves.Add(new Leave { Type = LeaveType.Paid, AvailableEntitlement = 15 }); //Assert var paidLeave = employee.Leaves.FirstOrDefault(l => l.Type == LeaveType.Paid); Assert.That(paidLeave, Is.Not.Null); Assert.That(paidLeave.AvailableEntitlement, Is.EqualTo(15)); } } }
This is not a meaningful test. The purpose is to show you an example of how tests are written in NUnit. Let me walk you through this test in order to understand it better. A unit test usually has three parts – Arrange
, Act
, and Assert
. You can see these commented in the preceding test.
In the Arrange
part, you set up everything that is required to run the test. In our example, we create a new instance of the Employee
class.
In the Act
part, we execute the code that is to be tested. In the preceding test, we add a Leave
object to the Leaves
collection of the Employee
class. This Leave
object is of the Paid
type having an entitlement of 15
.
In the Assert
part, we verify that the code that we wanted to test has behaved correctly. In the preceding test, we verify this by finding the Leave
object from the list of Leaves
whose type is Paid
. We confirm that such an object is present in the list and that AvailableEntitlement
has a value of 15
.
This was simple, wasn't it? If this is first time you are seeing tests, don't worry. We are going to see lot of these and we will get there together.