Thursday, December 1, 2016

Test driven development (TDD) with xunittest and .NET Core

We will create the test cases for .NET Core application named FizzBuzz. Here’s how it goes. If a number is divisible by 3 then you will call out Fizz. If a number is divisible by 5 then you will call out Buzz. If a number is divisible by 3 and 5 then you will call out FizzBuzz. Otherwise, you will just call out the number itself.

Here are some examples:

2 1 2
4 1 2 Fizz 4
5 1 2 Fizz 4 Buzz
15 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Fuzz 11 Fizz 13 14 FizzBuzz

The above table would represent our four test cases.

Directory & file structure

Create source (src) and test apps with the following directory and file structure:
image

In the root FizzBuzz directory, create a global.json file that contains the following content:
{
  "projects": [
    "src",
    "test"
  ]
}

Creating the business logic project

In a command line, while in the src/FizzBuzzLibrary directory, create the library project files by executing the following command:
dotnet new --type lib
Similarly, in a command line while the test/FizzBuzzTests directory, create the test project files by executing the following command:
dotnet new --type xunittest
If you open the FizzBuzz directory in Visual Studio Code, your directories & files will look like this:

image
 
Rename the src/FizzBuzzLibrary/Library.cs file to src/FizzBuzzLibrary/FizzBuzzMaster.cs. Open src/FizzBuzzLibrary/FizzBuzzMaster.cs in the editor and change the class name from Class1 to FizzBuzzMaster.
Similarly, rename test/FizzBuzzTests/Test.cs to test/FizzBuzzTests/FizzBuzzTestsMaster.cs. Open test/FizzBuzzTests/FizzBuzzTestsMaster.cs in the editor and change the class name from Tests to FizzBuzzTestsMaster.
Open the src/FizzBuzzLibrary/FizzBuzzMaster.cs file in the editor. Change the namespace to FizzBuzzLibrary and replace Method1() with the following method:
public string GetResult(int nmbr) {   
  string result = "";
  return result;
}
You will notice that the above method is destined to fail. This is the fundamental principal of test driven development whereby methods are built to fail.

We should create our test cases. Open test/FizzBuzzTests/FizzBuzzTestsMaster.cs in the editor and replace the Test1() method with the following four test cases:

[Fact]
public void Given2Result12() {
  FizzBuzzMaster fbm = new FizzBuzzMaster();
  var expected = "1 2 ";
  var actual = fbm.GetResult(2);
  Assert.Equal(expected, actual);
}

[Fact]
public void Given4Result12fizz4() {
  FizzBuzzMaster fbm = new FizzBuzzMaster();
  var expected = "1 2 Fizz 4 ";
  var actual = fbm.GetResult(4);
  Assert.Equal(expected, actual);
}

[Fact]
public void Given5Result12fizz4buzz() {
  FizzBuzzMaster fbm = new FizzBuzzMaster();
  var expected = "1 2 Fizz 4 Buzz ";
  var actual = fbm.GetResult(5);
  Assert.Equal(expected, actual);
}

[Fact]
public void Given15Result12fizz4buzzfizz78fizzbuzz11fizzfizz1314fizzbuzz() {
  FizzBuzzMaster fbm = new FizzBuzzMaster();
  var expected = "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz ";
  var actual = fbm.GetResult(15);
  Assert.Equal(expected, actual);
}
We need to make a reference to the Library project from the test project. This is done by adding the following dependency to the test/FizzBuzzTests/project.json file:
"FizzBuzzLibrary":{
  "target": "project"
}
The dependencies collection in test/FizzBuzzTests/project.json now looks like this:
"dependencies": {
  "System.Runtime.Serialization.Primitives": "4.1.1",
  "xunit": "2.1.0",
  "dotnet-test-xunit": "1.0.0-rc2-192208-24",
  "FizzBuzzLibrary":{
    "target": "project"
  }
}
We have built our preliminary business logic and test cases. In addition, we referenced our business logic application into our test cases application. Now let us test things out.

To restore, build and test Library application, execute the following commands from within the root FizzBuzz directory:
dotnet restore src/FizzBuzzLibrary
dotnet build src/FizzBuzzLibrary
dotnet restore test/FizzBuzzTests
dotnet build test/FizzBuzzTests
It is now time to run the actual tests. This is done by executing the following command also from within the root FizzBuss directory:

dotnet test test/FizzBuzzTests

The test execution shows the following results:

Project FizzBuzzLibrary (.NETStandard,Version=v1.6) was previously compiled. Skipping compilation.
Project FizzBuzzTests (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit win10-x64)
  Discovering: FizzBuzzTests
  Discovered:  FizzBuzzTests
  Starting:    FizzBuzzTests
    Tests.FizzBuzzTestsMaster.Given5Result12fizz4buzz [FAIL]
      Assert.Equal() Failure
                Γåô (pos 0)
      Expected: 1 2 Fizz 4 Buzz
      Actual:
                Γåæ (pos 0)
      Stack Trace:
        D:\scrap\_3973\FizzBuzz\test\FizzBuzzTests\FizzBuzzTestsMaster.cs(24,0): at Tests.FizzBuzzTestsMaster.Given5Result12fizz4buzz()
    Tests.FizzBuzzTestsMaster.Given2Result12 [FAIL]
      Assert.Equal() Failure
                Γåô (pos 0)
      Expected: 1 2
      Actual:
                Γåæ (pos 0)
      Stack Trace:
        D:\scrap\_3973\FizzBuzz\test\FizzBuzzTests\FizzBuzzTestsMaster.cs(12,0): at Tests.FizzBuzzTestsMaster.Given2Result12()
    Tests.FizzBuzzTestsMaster.Given15Result12fizz4buzzfizz78fizzbuzz11fizzfizz1314fizzbuzz [FAIL]
      Assert.Equal() Failure
                Γåô (pos 0)
      Expected: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fiz┬╖┬╖┬╖
      Actual:
                Γåæ (pos 0)
      Stack Trace:
        D:\scrap\_3973\FizzBuzz\test\FizzBuzzTests\FizzBuzzTestsMaster.cs(30,0): at Tests.FizzBuzzTestsMaster.Given15Result12fizz4buzzfizz78fizzbuzz11fizzfizz1314fizzbuzz()
    Tests.FizzBuzzTestsMaster.Given4Result12fizz4 [FAIL]
      Assert.Equal() Failure
                Γåô (pos 0)
      Expected: 1 2 Fizz 4
      Actual:
                Γåæ (pos 0)
      Stack Trace:
        D:\scrap\_3973\FizzBuzz\test\FizzBuzzTests\FizzBuzzTestsMaster.cs(18,0): at Tests.FizzBuzzTestsMaster.Given4Result12fizz4()
  Finished:    FizzBuzzTests
=== TEST EXECUTION SUMMARY ===
   FizzBuzzTests  Total: 4, Errors: 0, Failed: 4, Skipped: 0, Time: 0.229s
SUMMARY: Total: 1 targets, Passed: 0, Failed: 1.


Let’s fix all four failed tests by fixing our GetResult() method in src/FizzBuzzLibrary/FizzBuzzMaster.cs. Replace the GetResult() method with the following code:
public string GetResult(int nmbr) {   
  string result = "";

  for (int ndx=1; ndx<nmbr+1; ndx++) {
    if (ndx % 3 == 0 && ndx % 5 ==0) {
      result += "FizzBuzz ";
    } else if (ndx % 5 ==0 ) {
      result += "Buzz ";
    } else if (ndx % 3 ==0 ) {
      result += "Fizz ";                   
    }
    else
      result += ndx.ToString() + " ";
  }

  return result;
}
Build and run your tests again. This should be the outcome after you build and run your tests again:

Project FizzBuzzLibrary (.NETStandard,Version=v1.6) was previously compiled. Skipping compilation.
Project FizzBuzzTests (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit win10-x64)
  Discovering: FizzBuzzTests
  Discovered:  FizzBuzzTests
  Starting:    FizzBuzzTests
  Finished:    FizzBuzzTests
=== TEST EXECUTION SUMMARY ===
   FizzBuzzTests  Total: 4, Errors: 0, Failed: 0, Skipped: 0, Time: 0.161s
SUMMARY: Total: 1 targets, Passed: 1, Failed: 0.


We are happy that all our tests have successfully passed.






















No comments:

Post a Comment