Providing better quality by creating unit tests and integration tests

Building high-quality applications and satisfying application users is a difficult endeavor. Shipping products that have technical and functional flaws can lead to enormous problems during the maintenance phase of your applications.

The worst-case scenario is that, since maintenance is so demanding on time and resources, you won't be able to evolve your applications as quickly as possible to lower your time-to-market, and you will be unable to provide exciting new features. Don't think that your competition isn't waiting! They will surpass you and you will lose market shares and market leadership.

But how can you succeed? How can you reduce the time to detect bugs and functional problems? You have to test your code and your applications – and you have to do that as much as possible and as soon as possible. It is common knowledge that fixing a bug during development is cheaper and quicker, whereas fixing a bug during production takes more time and money.

Having a low MTTR (short for mean time to repair) for bugs can make a big difference when it comes to becoming a future market leader within your specific markets.

Let's divert a little and do some best practices housekeeping, which we will need to use in our application. In C#, we can check whether a string is null or empty using the String.IsNullOrEmpty() method. We need to do this because having a string that's null and having a string that's empty are two different scenarios altogether. An empty string is not necessarily null.

There are also situations when we're dealing with collections and we need to check whether the collection is null or empty. Unfortunately, we don't have an out-of-the-box implementation like the one we used for strings, which means we'll create it ourselves.

Let's go to the extensions folder and create a static class called CollectionsEtensionMethods that contains two methods, as follows:

 public static class CollectionsExtensionMethods
{
public static bool IsNullOrEmpty<T>(this IEnumerable<T>
genericEnumerable)
{
return (genericEnumerable == null) ||
(!genericEnumerable.Any());
}

public static bool IsNullOrEmpty<T>(this ICollection<T>
genericCollection)
{
if (genericCollection == null)
{
return true;
}
return genericCollection.Count < 1;
}
}

Now, we'll be able to implement IsNullOrEmpty() checks on any of our collections, that is, as long as we reference the TicTacToe.Extensions namespace from anywhere in our application. We will see this in action in the following code snippet, where we will be looking at game session turns and finding out whether they are null or empty.

Let's continue with the development of the Tic-Tac-Toe application and learn how to carefully test it in more detail:

  1. Add a new method called AddTurn to GameSessionService and update the game session service interface: 
public async Task<GameSessionModel> AddTurn(Guid id, string email, int x, int y)
{
var gameSession = _sessions.FirstOrDefault(session => session.Id
== id);
List<TurnModel> turns;
if (!gameSession.Turns.IsNullOrEmpty())
turns = new List<TurnModel>(gameSession.Turns);
else turns = new List<TurnModel>();
turns.Add(new TurnModel {User = await _UserService.GetUserByEmail
(email), X = x, Y = y });
if (gameSession.User1?.Email == email) gameSession.ActiveUser =
gameSession.User2;
else gameSession.ActiveUser = gameSession.User1;
gameSession.TurnFinished = true;
_sessions = new ConcurrentBag<GameSessionModel>(_sessions.Where(u
=> u.Id != id))
{ gameSession };
return gameSession;
}
  1. Add a new method called SetPosition to GameSessionController
        public async Task<IActionResult> SetPosition(Guid id,
string email, int x, int y)
{
var gameSession =
await _gameSessionService.GetGameSession(id);
await _gameSessionService.AddTurn(gameSession.Id,
email, x, y);
return View("Index", gameSession);
}
  1. Add a new model called InvitationEmailModel to the Models folder: 
public class InvitationEmailModel
{
public string DisplayName { get; set; }
public UserModel InvitedBy { get; set; }
public DateTime InvitedDate { get; set; }
public string ConfirmationUrl { get; set; }
}
  1. Add a new view called InvitationEmail to the Views/EmailTemplates folder: 
@model TicTacToe.Models.InvitationEmailModel
@{
ViewData["Title"] = "View";
Layout = "_LayoutEmail";
}
<h1>Welcome @Model.DisplayName</h1>
You have been invited by @($"{Model.InvitedBy.FirstName} { Model.InvitedBy.LastName} ") to play the Tic-Tac-Toe game.
Please click <a href="@Model.ConfirmationUrl">here</a> to join the game.
  1. Update the Index method in GameInvitationController to be able to use the invitation email template we mentioned previously: 
[HttpPost]
public async Task<IActionResult> Index( GameInvitationModel
gameInvitationModel, [FromServices]IEmailService
emailService)
{
var gameInvitationService = Request.HttpContext.
RequestServices.GetService<IGameInvitationService>();
if (ModelState.IsValid)
{
try
{
var invitationModel = new InvitationEmailModel
{
DisplayName = $"{gameInvitationModel.
EmailTo}",
InvitedBy = await
_userService.GetUserByEmail
( gameInvitationModel.InvitedBy),
ConfirmationUrl =
Url.Action("ConfirmGameInvitation",
"GameInvitation",
new { id = gameInvitationModel.Id },
Request.Scheme, Request.Host.ToString()),
InvitedDate = gameInvitationModel.
ConfirmationDate
};
var emailRenderService = HttpContext.
RequestServices.GetService
<IEmailTemplateRenderService>();
var message = await emailRenderService.
RenderTemplate<InvitationEmailModel>
("EmailTemplates/InvitationEmail",
invitationModel, Request.Host.ToString());
await emailService.SendEmail(
gameInvitationModel.EmailTo,
_stringLocalizer

["Invitation for playing a Tic-Tac-Toe
game"], message);
}
catch
{
}
var invitation = gameInvitationService.Add
(gameInvitationModel).Result;
return RedirectToAction
("GameInvitationConfirmation", new { id =
gameInvitationModel.Id });
}
return View(gameInvitationModel);
}
  1. Add a new method called ConfirmGameInvitation to GameInvitationController
   [HttpGet]
public IActionResult ConfirmGameInvitation(Guid id,
[FromServices]IGameInvitationService
gameInvitationService)
{
var gameInvitation = gameInvitationService.
Get(id).Result;
gameInvitation.IsConfirmed = true;
gameInvitation.ConfirmationDate = DateTime.Now;
gameInvitationService.Update(gameInvitation);
return RedirectToAction("Index", "GameSession", new
{ id
= id });
}
  1. Start the application and verify that everything is working as expected, including the various emails and steps for starting a new game.

Now that we have implemented all this new code, how do we test it? How do we ensure that it is working as expected? We could start the application in debug mode and verify that all the variables have been set correctly and that the application flow is correct, but that would be very tedious and not very efficient.

What would be better than doing this? Using unit tests and integration tests. We will look at these tests in the upcoming sections.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.114.29