This week, I was working on writing tests for my Shinny-SSG project. It was the most challenging lab in the OSD600 course since I had to modify both my code and my project's folder structure to implement the tests.
The testing framework that I chose is XUnit. The first reason is that it is trendy compared to another test framework such as NUnits. I created test method stubs from the existing code by Create Unit Tests command. To use it with Xunit, I have to implement the XUnit.net.TestGenerator extension to my project.
I want to test how my tools generated files and folders in the destination with different arguments passed to the program. However, in my old code, I put all the logic of working with arguments in the
static int main( string args) function. I could not use Interface and Dependency injection to mock the CommandLineApplication because CommandLineUtils does not have an interface for this class. Luckily, I found this guidance from the owner of CommandLineUtils, and he advised that "Split the command-line argument parser and application execution into separate class structures" to test various options programmatically. It is a great suggestion, and I rewrote my program by adding class CommandLineOptions and adding logic to the constructor of class Generator. I can kill two birds with one stone by this change: code refactoring and writing better tests.
Another problem I had was my folder structure. Before, I put the project's sln file, .git file , and src files in the root of the folder. However, when I added a new test project for Shinny-SSG, I had it outside my git folder, and it would be impossible to commit the change and put it in my remote repository. To resolve that, I had to change my folder structure to this:
C:. ├───shinny-ssg │ ├───bin │ │ ├───Debug │ │ │ └───netcoreapp3.1 │ │ │ ├───dist │ │ │ └───publish │ │ ├───Destination │ │ └───Release │ │ └───netcoreapp3.1 │ ├───obj │ │ ├───Debug │ │ │ └───netcoreapp3.1 │ │ └───Release │ │ └───netcoreapp3.1 │ ├───Properties │ └───src └───shinny-ssgTests ├───bin │ └───Debug │ ├───.netcoreapp,version=v3.1 │ └───netcoreapp3.1 ├───obj │ └───Debug │ ├───.netcoreapp,version=v3.1 │ └───netcoreapp3.1 └───src
I wrote 3 test for Generator class
run() function that cover 3 different cases: config file option, input path option and invalid input path option. My tests help uncovering a huge bug in my application. Before, I thought that
default keyword was used to specified the default value of a variable.
cssUrl = cssOption.HasValue() ? cssOption.Value() : default;
default literal is for producing the default value of a type that is null in this case ( CssUrl is the
I also wrote a test that testes the core feature of my application: Given a text and checked if the generated HTML value matched the expected output.
Throughout this experience, I learn a lot about software testing and why it is essential for software development. In the future, I will implement more tests for my project and explore other test frameworks.