Monday, April 29, 2019

TDD in JavaScript (Part 2)

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


In the previous post we setup Jasmine in preparation for a simple browser-based tic-tac-toe game. In this post we're going to actually write some tests and do some test-driven development for that game. First we need our requirements. Remember that in test-driven development our tests are written against the requirements and not the actual code. Without requirements we don't have any tests.

  1. In a game of tic-tac-toe we have a game board that has nine boxes arranged in a 3x3 pattern (3 columns and 3 rows)
  2. Our two players are Xs and Os.Xs go first.When X clicks on a box, that box is marked with an X and it becomes O's turn
  3. When O clicks on a box, that box is marked with an O and it becomes X's turn
  4. There are four possible outcomes to a game:
    • One player marks all three boxes in the same row
    • One player marks all three boxes in the same column
    • One player marks three boxes in a row diagonally
    • All boxes are selected and no player has achieved any of the other three outcomes
The rules are pretty straight forward so we should be able to generate some unit tests pretty easily from them.

A quick side not about Jasmine. Jasmine is a behavior-driven development framework, which implies a lot of things that aren't important to this post, but are important. We bring it up because our tests will be named differently than we've named them before. In Jasmine, each test is called a spec and the specs are grouped in logical blocks called describes. We recommend creating a new describe for each function you're going to test. Let's get set up to write our first spec.

I've created two new folders in tddjs: src and tests. In the tests folder, I'll create a new file called tic-tac-toe.spec.js. Because our application should be very simple we'll keep all of our specs in a single file. I'll also create a new file in the src folder called tic-tac-toe.js. Now that we have those two files (even though they're empty) we'll want to modify the SpecRunner.html file we got from Jasmine.

If you open SpecRunner.html you should see two sections marked with comments that indicate where you should include your source files and your spec files. Right now they likely reference files that we deleted earlier. We'll replace what's there with references to our two new files. SpecRunner.html now looks like this.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v2.8.0</title>

  <link rel="shortcut icon"
      type="image/png" href="lib/jasmine-2.8.0/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine-2.8.0/jasmine.css">

  <script src="lib/jasmine-2.8.0/jasmine.js"></script>
  <script src="lib/jasmine-2.8.0/jasmine-html.js"></script>
  <script src="lib/jasmine-2.8.0/boot.js"></script>

  <!-- include source files here... -->
  <script src="src/tic-tac-toe.js"></script>

  <!-- include spec files here... -->
  <script src="tests/tic-tac-toe.spec.js"></script>

</head>

<body>
</body>
</html>
Let's go ahead and open SpecRunner.html in our browser and take a look at what we have so far.



You should have something that looks very similar to this. We don't have any specs (tests) yet so nothing ran. That's fine. Now it's time to write our first test. Remember that in test-driven development our tests will always fail first.

We'll create a describe for a function we'll call selectBox in tic-tac-toe.spec.js.

describe('selectBox', () => {});
There's not much to see there because we still don't have our first spec written. We can add it easily enough.

describe('selectBox', () => {
  it('should mark the box with the current players marker', () => {});
});
Our Jasmine tests are named a little bit more plainly than our other types of tests. The language and constructs in Jasmine are designed to read like English. That is, our test should actually be read like this: "selectBox should mark the box with the current players marker". That allows us to easily correlate our tests with our requirements and share those results with our business customers if we want. This is a feature of behavior-driven development.

If you refresh SpecRunner.html in your browser you should now see a message indicating that you have a spec, it passed, but it has no expectations. That's great! It's not actually passing, but it's not failing either. Let's change our test to make it fail.

describe('selectBox', () => {
  it('should mark the box with the current players marker', () => {
 // arrange
 const element = document.getElementById('topLeft');
 element.innerHTML = ' ';
 
 // act
 element.click();
 
 // assert
 expect(element.innerHTML).toBe('X');
  });
});
This test simply tries to get an element from the page that has an id of topLeft. We make sure the element isn't already marked with anything by setting its innerHTML property to a non-breaking space. We click the element, then check to make sure its innerHTML property is now set to X. When we refresh SpecRunner.html we should now see that we have one failing test.


Jasmine tells us right away not only that we have a failing test, but also why our test is failing. In this case we can see that our test is failing because we tried to access the innerHTML property of an element that didn't exist. This is where things get a little bit more complicated. What we need to do now is create an element with the id we're looking for before our test runs.

describe('selectBox', () => {
  it('should mark the box with the current players marker', () => {
    // arrange
    const elementToCreate =  document.createElement('button');
    elementToCreate.id = 'topLeft';
    elementToCreate.innerHTML = ' '
    document.body.appendChild(elementToCreate);
    const element =  document.getElementById('topLeft');
 
    // act
    element.click();
 
    // assert
    expect(element.innerHTML).toBe('X');
  });
});
With this change we're using JavaScript to programmatically add a button to our document so we can access it and click on it later. Our test still fails because clicking on our button doesn't actually do anything yet.


This time we see a couple of new things on SpecRunner.html. First, we see that the reason for the failed test has changed. We now see that the failure is caused by our expectation not being met. This is good news because it means our test is running properly, but what we expect to happen isn't happening. The second thing we see that's new is there is now a button on the document in SpecRunner.html. You can see it there in the bottom left of the screenshot.

Let's add the functionality to give our new button a click event and tell it to invoke the function selectBox when it is clicked. We'll want to pass the element being clicked into the selectBox function. We'll also add a little bit of cleanup to remove the button from the document when our test finishes. This helps keep SpecRunner clean, but it will also have greater implications as we add more tests.

describe('selectBox', () => {
  it('should mark the box with the current players marker', () => {
    // arrange
    const elementToCreate =  document.createElement('button');
    elementToCreate.id = 'topLeft';
    elementToCreate.innerHTML = ' '
    elementToCreate.onclick = selectBox(elementToCreate);
    document.body.appendChild(elementToCreate);
    const element =  document.getElementById('topLeft');
 
    // act
    element.click(element);
 
    // assert
    expect(element.innerHTML).toBe('X');

    // cleanup
    document.body.removeChild(elementToCreate);
  });
});
Our test still fails, but this time it's failing for exactly the right reason: there is no selectBox function. Also notice that the button is not showing up anymore.


Since we're going to do this iteratively (like we're supposed to) we can go ahead and add a selectBox function to our tic-tac-toe.js file.

function selectBox() { }
We're back to having a failing test because our expectation is not being met. That makes sense because nothing is happening in our actual code yet. Now we can add the code that updates the innerHTML property of the element that was clicked.

function selectBox(element) {
    element.innerHTML = 'X';
}
Our test is passing now! Astute readers will notice that our code doesn't currently correctly implement our requirements, but that's OK for right now. Right now we've written a single test that tests a single piece of code and that test passes.

We're going to take another break here. At this point we know how to setup Jasmine, write our first test, and get it to pass. In the next installment we'll add more tests and try to get closer to having a working game of Tic Tac Toe.


Sunday, April 28, 2019

TDD in JavaScript (Part 1)

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


We've heard from some front-end developers that test-driven development isn't possible or useful for them. We (obviously) couldn't disagree more so we decided to put together a quick guide to using test-driven development to create a pure JavaScript application. We prefer the Jasmine testing framework so that's what we're going to demonstrate here.

First off, if this is the first time you've heard of Jasmine you might want to check out their official site (the link is in the Resources section at the bottom of this post).

Whether you want to check out their site or not, you're going to need to go there to get the framework. Don't worry, it's a small download and they have it available in .zip and .tar format. You can just go straight to the link in the Resources section if you don't want to browse their site.

To keep things simple I created a directory called "tddjs" on my desktop and unzipped the file I downloaded straight into that directory. Here's what my folder looks like.


Their download now includes some sample code of their own (in the src and spec folders), but we don't need that. For this guide we are only interested in keeping the contents of the lib/jasmine-2.8.0 directory and the SpecRunner.html file in the root. I'm going to go ahead and delete the other files. Here's what my folder looks like now.

Looking into the lib/jasmine-2.8.0 folder we see 6 files:

boot.js

console.js

jasmine.css

jasmine.js

jasmine-favicon.png

jasmine-html.js

jasmine.js contains the actual Jasmine testing framework, jasmine-html.js contains some functions that help format the page, and boot.js initializes Jasmine.

Now that we have Jasmine ready we need some code to test. *record scratch* Oops. We need some tests. We're going to create a simple tic-tac-toe game. This should allow us to focus on the functionality we expect instead of getting bogged down in how things look. This is actually a really good stopping point so we're going to break here. We should be able to wrap things up in our next post.

Resources

Official Jasmine Home Page

Download Jasmine


Saturday, April 27, 2019

Do I Still Need QA If I Use TDD?

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


One of the most common misconceptions we hear about test-driven development (TDD) - and thorough unit testing in general - is that once it is implemented you no longer need to do any quality assurance (QA). We'll explain in this post a few reasons why you definitely still want to do QA and probably some user acceptance testing (UAT) as well.

The primary reason you still want to make sure you're doing QA when you're doing TDD is that TDD focuses on testing the units of code. If you read our guide you may recall that units can be as small as a single method or as large as an entire class (encompassing many methods that work together, but with a single purpose). But even when all of our tests pass and we've tested every possible permutation and combination of variables we still don't know whether our software actually works. All we know is that the individual parts work in isolation from each other.

Think about a few parts of a car that work together: the ignition switch, the starter, and the engine. Our unit tests have verified that the ignition switch engages when the key is in the proper position. They've verified that given an electrical current, our starter engages the flywheel. They've verified that when the flywheel is engaged the engine starts. We know that all of the individual parts of the car are working properly in isolation, so our QA process is to essentially make sure we've assembled those pieces properly. These tests are generally referred to as integration or end-to-end tests.

Thinking in terms of code again our unit tests will verify that a function works as expected with a given set of inputs. An integration test will verify that the button on the user interface actually invokes that function with the expected set of inputs. An end-to-end test will verify that when a user visits the page and provides all of their information and clicks the button, a new login is created and they are able to sign in to the application.

A secondary benefit of formal QA is simply getting a "second set of eyes" on the functionality. When we use TDD to write our tests and our code, it is most often the same person doing both. So when the developer delivers that software she is the only person who has really looked at what it does and how (and whether) it works. Having a QA team review it is a good safety check to make sure the developer didn't miss anything.

Although the use of TDD will significantly reduce the number of bugs, it will very rarely eliminate them completely. Having a QA person or team review the delivered software against the acceptance criteria is a really important step to make sure the maximum amount of bugs has been discovered prior to a demo.

Finally, in Agile (Scrum in particular) it is important to remember that the development team is responsible for delivering the code, it is up to the product owner (and stakeholders) to decide when to release that code for consumption. It is highly recommended that at least some testing is performed by at least a small subset of end users (this could mean stakeholders or a limited beta release or even using feature flags to enable the new features for a very small subset of users) before the product is made widely available. Just as QA looks for different things than unit tests, end users will look for different things than QA. Ideally, by the time our product goes to demo at the end of our sprint we will have identified and resolved technical bugs ("I clicked the button and nothing happened"). But the UAT process will help us identify whether we had some unknown issues in our requirements or somewhere else along the way ("Why can I choose to withdraw pennies from an ATM that only has $20 bills in it?").

Although TDD is a wonderful tool to reduce defects, it is only one tool in the overall testing belt. Just like the hammer is good for hammering in nails, we need to use other tools for other parts of the job.


Friday, April 26, 2019

Who Needs Test-Driven-Development?

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.

Recently, a seasoned developer asked a question of ThoroughTest that we wanted to answer for the community at-large: "Do really good developers need test-driven development?" The short answer is yes, absolutely, unequivocally, definitely. Unfortunately, that's not very convincing so we'll try to explain exactly why we feel that way.

First, let's address the elephant in the room on this one. ThoroughTest is a business and our business is training and certifying organizations and individuals on the concepts and processes of test-driven development. The short version is that we stand to make money when more people get on board with test-driven development. There's no getting around that. And although we want you to become a certified test-driven development practitioner with us, the truth is we feel passionately about helping people write quality software and we strongly believe that using test-driven development is one of the best ways to make that happen. Now that we've cleared that up, let's talk about why even really good developers need test-driven development.

If you are a really good developer and you don't work on a team of other developers and you always write your own requirements and you work for yourself at your own company and you don't care about realizing all the advantages of test-driven development then no, you don't need test-driven development. If, however, you live in the real world then the question isn't really about whether you as an individual need (or would benefit from) test-driven development. Test-driven development is an organization-wide effort that is most successful when everyone from the highest executive to the lowest intern is on board with it.

Organizational commitment aside, really good developers benefit from test-driven development just as much as brand new developers. We discussed five benefits of test-driven development in an earlier post and really good developers would still reap all of those benefits. Even if a really good developer already feels like she doesn't usually have problems understanding requirements, the process of discussing those requirements with the product owner in the context of how to test them will result in better communication between the developer, product owner, and even the QA team.

Since test-driven development isn't about making individual developers better, there's no point on the "good developer" scale where the benefits would be lost. One of the benefits of utilizing test-driven development that we didn't mention in our previous post was the stability of the code base going forward. As developers, we all know that there will almost definitely come a day when our beautiful, perfect, pristine code will have to be modified and we may not be the person who gets to make those modifications. By using test-driven development initially we'll be confident that future changes won't break what we've spent so much time creating, even if those future changes are made by a developer who is not "really good".

If you're considering making the transition to test-driven development, but you're not sure whether you personally would benefit from it, try to remember that this method of writing software is designed to benefit the entire team, division, and organization. So yes, even really good developers need test-driven development.


Thursday, April 25, 2019

Five Good Reasons to Use Test-Driven Development

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


When it comes to test-driven development, many developers want to know why it is better to write tests before code instead of the other way around. This is a great question and is truly a stumbling block for a lot of people when it comes to climbing on board the test-driven development train. The main way we hear this question phrased is "Why can't I just write my tests after my code is complete so I know what I'm testing?" Of course you can write your code first, and there isn't necessarily anything wrong with that approach. It's just not as beneficial as writing your tests first. In this article we'll discuss the five major reasons why writing tests first is more advantageous than writing code first.

A Better Understanding


The first benefit you'll see when writing your tests first is a more thorough understanding of the requirements. This is sort of an added bonus of test-driven development. It has been our observation that when developers write the unit tests first, based on the requirements, they are more likely to identify shortcomings in those requirements, and are also more inclined to seek clarification. Since the developers haven't written any code yet, they aren't worried about scrapping anything as the requirement gets clarified.

Write Less Code


The second benefit developers encounter is that they write less actual code. In our experience, most developers are willing to dive right in and start writing the best, coolest, most extravagant code they can imagine. As long as what they end up with satisfies the requirements they don't have anything to worry about. The problem with that approach is that the neat bells and whistles we tend to spend our time on aren't necessarily important to the product owner (or end users). When we use test-driven development all the way through the process, we see developers spend time only writing code that satisfies requirements. Bells and whistles can still be added, but they are more deliberately added by creating requirements around them. This actually goes back to the first benefit of test-driven development. When developers understand what the product owner wants it is easier to stay focused on that goal and deliver something that satisfies everyone in the allocated time.

Better Design


The third benefit of test-driven development is that it helps enforce SOLID design principles, which will almost always lead to better code. Test-driven development usually requires some form of dependency injection (D: Dependency Inversion), provide the developer an opportunity to keep classes focused (S: Single Responsibility and I: Interface Segregation), and helps enforce the idea of swapping out concrete implementations at runtime (L: Liskov Substitution Principle). Writing better, more extensible, more maintainable code should always be the goal of the development team, and test-driven development will inherently work to that end.

Faster Development


This brings us to the fourth significant advantage of test-driven development: timeliness. If you've read our guide you'll know that test-driven development goes pretty hand-in-hand with Agile development methodologies. One of the 12 principles of Agile is to "deliver working software frequently" and test-driven development helps with that. When developers are able to understand the requirements better and stay focused on what the product owner wants delivered, they spend less time adding features no one asked for, which shortens the development cycle, which allows more working software to be delivered more frequently.

Faster Delivery


The fifth advantage of test-driven development goes hand-in-hand with the fourth: the overall release cycle is shorter. In addition to shorter development cycles organizations will see shorter QA stages with fewer bugs discovered, shorter user acceptance testing stages, and fewer bugs reported in production. Since the developers and product owner clarified the requirements before any code was written, the QA team has a clearer understanding of what the final software should do. This allows them to create much more targeted tests. There is also the added bonus that QA will find less nuisance bugs (e.g. a system failure when a field is left empty), which requires less re-work and allows the QA team more time to find major bugs. When the product passes QA and goes out for user acceptance testing, the product owner isn't surprised by anything she didn't ask for in the development process. Since the developers received clarification at the beginning of the process, there is less room for ambiguity and fewer reports of issues from users. Finally, once the code does reach production, more bugs have been found throughout the development and approval process, which means there are fewer bugs actually released into the wild. In addition to better uptime and customer satisfaction, this also means developers won't have to stop work on new features to fix user-reported bugs in production code.

So can't these benefits be realized by writing tests after the code is complete? Since all of the advantages we've listed here build off the first one, and that first one provides clearer requirements, there's really no way to duplicate these benefits if we write our code first. Just as it is better to have coded unit tests than to not have coded unit tests, it is better to use test-driven development to write those coded unit tests than it is to write them after the code is complete. Although there are many more smaller benefits of writing your tests first, we feel these five provide the most compelling argument in favor of test-driven development.


Wednesday, April 24, 2019

Test-Driven Development in SQL Server

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


We've heard from a few developers working with SQL Server that they're having a hard time justifying test-driven development of their "code" when a lot of their logic resides in stored procedures. That's a valid point: why use test-driven development (or write unit tests at all) if you can't cover the entire codebase? Well, that's a larger topic that we may discuss in a future post, but for now we can resolve the issue by introducing a method for unit testing SQL Server objects with the tSQLt testing framework.

For starters, you can check out the official documentation of tSQLt by visiting their website. We'll use the rest of this post to show a few simple ways we can do test-driven development using the framework. Keep in mind that this is a limited overview of what tSQLt provides and can do so just because you don't see a solution for your scenario here doesn't mean they don't have one. Review their official docs to get a more thorough understanding of what's possible.

For these examples we'll create a database called CookBook. You can create it on any instance of SQL Server (including Express) and any version since 2005. This database will be a repository for our recipes so we'll create two tables and one join table: Recipe, Ingredient, and RecipeIngredient. You can use the scripts below to follow along.

CREATE TABLE Recipe
  (
     Id          INT IDENTITY(1, 1),
     Name        VARCHAR(100) NOT NULL,
     DateCreated DATETIME2 DEFAULT GETDATE()
  )

ALTER TABLE Recipe
  ADD CONSTRAINT PK_Recipe_Id PRIMARY KEY CLUSTERED (Id)

CREATE TABLE Ingredient
  (
     Id          INT IDENTITY(1, 1),
     Name        VARCHAR(100) NOT NULL,
     DateCreated DATETIME2 DEFAULT GETDATE()
  )

ALTER TABLE Ingredient
  ADD CONSTRAINT PK_Ingredient_Id PRIMARY KEY CLUSTERED (Id)

CREATE TABLE RecipeIngredient
  (
     Id           INT IDENTITY(1, 1),
     RecipeId     INT NOT NULL,
     IngredientId INT NOT NULL,
     Amount       DECIMAL(4, 2) NOT NULL,
     Measurement  VARCHAR(100) NOT NULL
  )

ALTER TABLE RecipeIngredient
  ADD CONSTRAINT PK_RecipeIngredient_Id PRIMARY KEY CLUSTERED (Id)

ALTER TABLE RecipeIngredient
  ADD CONSTRAINT FK_RecipeIngredient_Ingredient FOREIGN KEY (IngredientId)
  REFERENCES Ingredient(Id)

ALTER TABLE RecipeIngredient
  ADD CONSTRAINT FK_RecipeIngredient_Recipe FOREIGN KEY (RecipeId)
  REFERENCESRecipe(Id) 
Now that we have our table structure we want to create a stored procedure that gets all the ingredients for a specific recipe in our cook book. We want to see the Ingredient Name, Amount, and Measurement for each item in the recipe and we want to specify the recipe by name. We know our requirements so now we can write our tests. Before we can start writing tests that will actually work we need to install the tSQLt framework, which is pretty simple to do. We just download the zip file, unzip it, and run SetClrEnabled.sql followed by tSQLt.class.sql on your database. Now that the framework is installed it's time to write a unit test.

The first thing we want to do is create a test class, which will be used to group our tests together. We prefer to create test classes with the name of the stored procedure followed by ".Tests" to be clear what's being tested and that it is a test class. Since a test class is just a schema we should see a new schema created after we take this action.

EXEC tsqlt.Newtestclass 'GetIngredientsByRecipeName.Tests' 
Now we have a test class for our stored procedure (which you'll notice we plan to name GetIngredientsByRecipeName) and we can create our first actual test. Tests in tSQLt are just stored procedures named a specific way so we can use our existing TSQL skills to create our tests. The first thing we need to do in our test stored procedure is setup our data, which we can do by having tSQLt create fake tables for the tables we'll need. Once we have our fake tables we can populate them with fake data. By using fake data we'll be sure that our tests will always pass without having to worry about what recipes are actually in the database. Here's what we have so far:

CREATE PROCEDURE
[GetIngredientsByRecipeName.Tests].[Test that all ingredients are returned]
AS
  BEGIN
      -- Arrange
      EXEC tsqlt.FakeTable
        'Recipe'

      EXEC tsqlt.FakeTable
        'Ingredient'

      EXEC tsqlt.FakeTable
        'RecipeIngredient'
  END 
The FakeTable procedure opens a transaction, renames the table being passed, then recreates a table with the same name and structure, but without any constraints, defaults, or triggers. After the code above runs, all three tables will be empty shells of their normal selves, allowing us to populate whatever data we want into them. We'll populate our fake tables with some fake data so we can anticipate the results of our stored procedure.

INSERT INTO Recipe(Id,Name) VALUES(1,'Grilled Cheese')

INSERT INTO Ingredient (Id, Name)
VALUES(1, 'Butter'), (2, 'Cheddar Cheese'), (3, 'White Bread')

INSERT INTO RecipeIngredient (RecipeId, IngredientId, Amount, Measurement)
VALUES(1, 1, 1, 'Tbsp'), (1, 2, 1, 'Slice'), (1, 3, 2, 'Slices')

INSERT INTO Recipe (Id, Name) VALUES(2, 'Quesadilla')

INSERT INTO Ingredient (Id, Name) VALUES(4, 'Tortilla')

INSERT INTO RecipeIngredient (RecipeId, IngredientId, Amount, Measurement)
VALUES(2, 4, 1, 'Tortilla'), (2, 2, .5, 'Cups')
Note: Even though we could normally exclude inserting values into the Id fields of Recipe and Ingredient (because they are identity fields and should automatically get the next number) we have to explicitly include them in our test because the fake tables are created without identity fields.

Now we have two recipes' worth of fake data and we know what we expect our stored procedure to do. We're going to want to compare the results of our stored procedure to what we expect so we'll create a temp table to store the results and a temp table containing our expected results.

CREATE TABLE #temp
  (
     IngredientName VARCHAR(100),
     Amount         DECIMAL (4, 2),
     Measurement    VARCHAR(100)
  )

CREATE TABLE #expected
  (
     IngredientName VARCHAR(100),
     Amount         DECIMAL (4, 2),
     Measurement    VARCHAR(100)
  )

INSERT INTO #expected
VALUES('Butter', 1, 'Tbsp'), ('Cheddar Cheese', 1, 'Slice'), ('White Bread', 2, 'Slices')

-- Act
INSERT INTO #temp
EXEC GetIngredientsByRecipeName 'Grilled Cheese' 
Finally, we'll actually compare the results of the two tables by executing the AssertEqualsTable procedure from the tSQLt framework. This procedure compares the contents of two tables for equality. Since we want to confirm multiple values across multiple rows, this option makes the most sense for us.

-- Assert
EXEC tsqlt.AssertEqualsTable '#temp', '#expected' 
Now we can create the stored procedure and run it using the Run procedure from tSQLt and passing either the test class or the test name to the procedure as a parameter. We'll use the test class name because going forward we'll want all of our tests to run whenever we make a change to our stored procedure. This is a good habit to get into now.

EXEC tsqlt.Run 'GetIngredientsByRecipeName.Tests' 
Good news; the test failed! There is no stored procedure named GetIngredientsByRecipeName yet so the test failed. We've established our first Red step in test-driven development! Create the procedure, but don't put anything in it yet.

CREATE PROCEDURE GetIngredientsByRecipeName
(
    @RecipeName VARCHAR(100)
)
AS
BEGIN
    PRINT 'Called'
END 
Run the test again and look at the output. This time, instead of getting an error message that it "could not find stored procedure 'GetIngredientsByRecipeName'" we see "(Failure) Unexpected/missing resultset rows!" and then a description of how the two tables failed to match. For more details on how to read this output, check out the tSQLt docs for AssertEqualsTable.

Let's finally modify our stored procedure to do what we want it to do: get the ingredients for the specified recipe.

CREATE PROCEDURE GetIngredientsByRecipeName
(
    @RecipeName VARCHAR(100)
)
AS
BEGIN
    SELECT
         Ingredient.Name
        ,RecipeIngredient.Amount
        ,RecipeIngredient.Measurement
    FROM Ingredient
    INNER JOIN RecipeIngredient
        ON Ingredient.Id = RecipeIngredient.IngredientId
    INNER JOIN Recipe
        ON RecipeIngredient.RecipeId = Recipe.Id
    WHERE  Recipe.Name = @RecipeName
END 
When we run our test one more time we see that it passed. Now we have our Green step so we'll review our stored procedure for any opportunities to improve. We don't see any so our Refactor step is complete without any changes.

We've got a new requirement that ingredient amounts should be summed up when the same ingredient is in the same recipe with the same measurement more than once. First we'll write the test:

CREATE PROCEDURE
  [GetIngredientsByRecipeName.Tests].
   [Test that ingredient amounts are summed]
AS
BEGIN
    -- Arrange
    EXEC tsqlt.FakeTable 'Recipe'

    EXEC tsqlt.FakeTable 'Ingredient'

    EXEC tsqlt.FakeTable'RecipeIngredient'

    INSERT INTO Recipe (Id, Name) VALUES(1, 'Salt Soup')

    INSERT INTO Ingredient (id, Name)
      VALUES (1, 'Salt'),
        (2, 'Chicken Broth'), (3, 'Carrots'), (4, 'Leather Boot')

    INSERT INTO RecipeIngredient(
      RecipeId,
      IngredientId,
      Amount,
      Measurement
    )
      VALUES (1, 1, 1, 'Tbsp'), (1, 2, 10, 'Cups'),
        (1, 3, 10, 'Carrots'), (1, 4, 1, 'Boot'), (1, 1, 16, 'Tbsp')

    CREATE TABLE #temp
      (
         IngredientName VARCHAR(100),
         Amount         DECIMAL (4, 2),
         Measurement    VARCHAR(100)
      )

    CREATE TABLE #expected
      (
         IngredientName VARCHAR(100),
         Amount         DECIMAL (4, 2),
         Measurement    VARCHAR(100)
      )

    INSERT INTO #expected
      VALUES ('Salt', 17, 'Tbsp'), ('Chicken Broth', 10, 'Cups'),
        ('Carrots', 10, 'Carrots'), ('Leather Boot', 1, 'Boot')

    -- Act
    INSERT INTO #temp
    EXEC GetIngredientsByRecipeName 'Salt Soup'

    -- Assert
    EXEC tsqlt.AssertEqualsTable '#temp', '#expected'
END 
Then we'll run all of the tests in the test class:

EXEC tsqlt.Run 'GetIngredientsByRecipeName.Tests' 
We get an exception: "(Failure) Unexpected/missing resultset rows!". We update the stored procedure:

ALTER PROCEDURE GetIngredientsByRecipeName
(
    @RecipeName VARCHAR(100)
)
AS
BEGIN
    SELECT
         Ingredient.Name
        ,SUM(RecipeIngredient.Amount)
        ,RecipeIngredient.Measurement
    FROM Ingredient
    INNER JOIN RecipeIngredient
        ON Ingredient.Id = RecipeIngredient.IngredientId
    INNER JOIN Recipe
        ON RecipeIngredient.RecipeId = Recipe.Id
    WHERE  Recipe.Name = @RecipeName
    GROUP BY
       Ingredient.Name
      ,RecipeIngredient.Measurement
END 
And finally we run all of our tests again:

EXEC tsqlt.Run 'GetIngredientsByRecipeName.Tests' 
This time our test summary shows that we have two tests that ran and both of them passed.

Stored procedures are an important part of database programming and sometimes play a large role in applications and architecture. Using the tSQLt framework we can realize the advantages of test-driven development even when we're working with SQL Server.

Tuesday, April 23, 2019

Letting Microsoft do the Wrapping with Fakes and Stubs

This blog post was originally published on the ThoroughTest website, back when that was a thing. As a co-founder and primary content contributor for ThoroughTest, I absolutely own the rights to this post and the source code to which it refers. I intend to reproduce each blog post here on my personal blog since the company is no longer in business.


We previously talked about creating our own wrappers for dependencies that do not have mockable interfaces. Specifically we showed how to wrap Microsoft's Random class in a wrapper so we could mock the return and confirm that we were making the calls. There's a slightly different way we can do this, using something Microsoft has included for a few years, called Fakes (and Stubs, too).

Note: Unfortunately, Fakes don't seem to be available for .Net Core just yet so we'll have to cross our fingers and hope they add that support soon.

Using Fakes and Stubs is actually kind of the same process as writing our own wrappers, except we don't have to write our own wrappers. Since we've already talked about why we'd wrap Random, we won't go into it again here. Instead we'll jump right into the "hows" of getting things up and running.

The first thing we need to do is create a fake for whatever namespace the class we're going to fake or stub is in. In this case, Random is in System so we need to create a fake of that assembly. To do that, we expand References in our test project, right-click on System and choose "Add Fakes Assembly" from the context menu. After a moment, there will be a new folder in the project called Fakes with two files in it: mscorlib.fakes and System.fakes. After another moment you will see references to those new files in the References for the project: mscorlib.4.0.0.0.Fakes and System.4.0.0.0.Fakes (the version numbers may be different, depending on what's out there when you read this). You should also see a new reference to Microsoft.QualityTools.Testing.Fakes. Here's a picture of what you might see:

Now that we've added the right references we'll get started with writing our tests themselves. First we have to create a ShimsContext to run our tests in. ShimsContext implements IDisposable so we can do this by utilizing a using statement:

   1:  // create the ShimsContext in order to use Fakes later
   2:  using (ShimsContext.Create())
   3:  {
   4:  }
Within the ShimsContext we can use Fakes to specify the exact data we want to receive when we use static methods. The first method here specifies that when DateTime.Now is called by the code under test, it should be detoured to use “09/12/2017” (we want our shuffler to shuffle two decks on Tuesdays so we always want this specific test to behave as though it is running on a Tuesday):

System.Fakes.ShimDateTime.NowGet = () => new DateTime(2017, 09, 12);
That's all we need to do in order for this test to work. When DateTime.Now is called by our Code Under Test, the call will get intercepted and re-routed to use 09/12/2017 instead of today's actual date. This way we've guaranteed that the day will always appear to be a Tuesday when this test is run. Here's the full test:

   1:  [TestMethod]
   2:  public void ShuffleShouldShuffleTwoDecksOnTuesdays()
   3:  {
   4:      // create the ShimsContext in order to use Shims later
   5:      using (ShimsContext.Create())
   6:      {
   7:          // arrange
   8:          // intercept the call to System.DateTime.Now and always return a date
   9:          // that we're sure falls on a Tuesday (09/12/2017 is a Tuesday)
  10:          System.Fakes.ShimDateTime.NowGet = () => new DateTime(2017, 09, 12);
  11:          var shuffler = new Shuffler();
  12:   
  13:          // act
  14:          var cards = shuffler.Shuffle();
  15:   
  16:          // assert
  17:          Assert.AreEqual(104, cards.Count);
  18:      }
  19:  }
Stubs are a little bit easier to work with and don't require the ShimsContext in order to use them. We can create a stub pretty easily by specifying which methods we want to stub for the stubbed object. Perhaps an example would be best here.

   1:  var randomStub = new System.Fakes.StubRandom
   2:  {
   3:      NextInt32Int32 = (minValue, maxValue) =>
   4:      {
   5:          if (position == 1)
   6:          {
   7:              position = 53;
   8:          }
   9:          position--;
  10:          return position;
  11:      }
  12:  };
Once we've created the stub we need a way to provide it to the Code Under Test, which brings us all the way back around to dependency injection. We can either provide the dependency in the constructor or we can create a public setter to do so. In these tests we're using Setting Injection to show how it would be done since our ThoroughTest guide focuses more on Constructor Injection. Here's the test in full to get a better idea of what's happening:

   1:  [TestMethod]
   2:  public void ShuffleShouldShuffleDeck()
   3:  {
   4:      // arrange
   5:      var position = 53;
   6:      // setup the Random stub so that when Next is called with two
   7:      // integers (min value and max value) we always return a number
   8:      // we know
   9:   
  10:      // what we're going to do here is go backward through the unshuffled
  11:      // deck so the "shuffled" deck that we end up with will just be an
  12:      // inversion of the unshuffled deck (KS will be first and AH will be last)
  13:      var randomStub = new System.Fakes.StubRandom
  14:      {
  15:          NextInt32Int32 = (minValue, maxValue) =>
  16:          {
  17:              if (position == 1)
  18:              {
  19:                  position = 53;
  20:              }
  21:              position--;
  22:              return position;
  23:          }
  24:      };
  25:   
  26:      var unshuffledDeck = new List<string>
  27:      {
  28:          "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "10H",
  29:          "JH", "QH", "KH", "AD", "2D", "3D", "4D", "5D", "6D", "7D",
  30:          "8D", "9D", "10D", "JD", "QD", "KD", "AC", "2C", "3C", "4C",
  31:          "5C", "6C", "7C", "8C", "9C", "10C", "JC", "QC", "KC", "AS",
  32:          "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "10S", "JS",
  33:          "QS", "KS"
  34:      };
  35:   
  36:      var shuffler = new Shuffler { Random = randomStub };
  37:   
  38:      // act
  39:      var cards = shuffler.Shuffle();
  40:   
  41:      // assert
  42:      var j = 51;
  43:      for (var i = 0; i < 51; i++)
  44:      {
  45:          Assert.AreEqual(unshuffledDeck[i], cards[j]);
  46:          j--;
  47:      }
  48:  }
You can see that we're creating an instance of the Shuffler class and then we're setting the Random property in that instance to the stub we created previously. It's important to note that we did not have to create a new ShimsContext in order for this to work properly. Fakes require the ShimsContext, but Stubs do not.

There's a lot we can do with Fakes and Stubs from Microsoft, but probably the best part is that this all comes out of the box with Visual Studio so we don't need to write our own wrappers or anything.