iPlexor/Hello-GitHub
A simple, but silly C# Hello World project. Purely for the sake of having at least one public GitHub repo.
Hello World
Since I can't publicly share 99.999% of my code on GitHub, here's a simple Hello World program in C# to show you how not to code.
Realistically, this is a MarkDown project about problem solving with snippets of C#, exposeing how bloody silly and frustrating coding can be.
Technically its the default project template for a C# Console App, but we can't ๐ฏ% test that. A crying shame, because this is ostensibly a 1 line program thanks to Top Level Statements. But the whole thing unravels quickly if you have the audacity to test it.
#TLDR Probably don't.
Starting Template
Problem 1: Making it testable
So to make it testable, we add a test project.
- Add an
XUnittest project. - Add a reference the
HelloWorldproject.Error: Main is inaccessible, your tests can't see it.
This is frustrating, but by default Top Level Statements gives you this implementation under the hood:
internal class Program
{
static void Main(string[] args)
{
// This is a simple C# program that prints "Hello, World!" to the console.
Console.WriteLine("Hello, World!");
}
}The internal for Program looks promising, but sadly Main defaults to private. That's our problem.
So we lose our beautiful 1-liner, just so we can set Program and Main to public.
Cool, now we can add tests and they'll pass.
Pro Tip: If you're doing TDD, remember to pretend you wrote the failing tests before you wrote the code to make them pass.
namespace HelloWorld.Tests;
public class HelloWorldTests
{
[Fact]
public void HelloWorld_Prints_HelloWorld()
{
// Arrange
var writer = new StringWriter();
Console.SetOut(writer);
// Act
Program.Main(default!);
// Assert
Assert.Equal("Hello, World!", writer.ToString().Trim());
}
[Fact]
public void HelloWorld_Never_Wawaweewah()
{
// Arrange
var writer = new StringWriter();
Console.SetOut(writer);
// Act
Program.Main(default!);
// Assert
Assert.NotEqual("Wawaweewah!", writer.ToString().Trim());
}
}Great! Now everything is public. ๐คฆโโ๏ธ Inconceivable!
We'll fix that later.
Problem 2: Measuring Code Coverage
The easy, but very expensive way to do this is to buy a Visual Studio Enterprise license and switch Code Coverage on. If you prefer to save a few grand a year, you're not going to do that.
Instead, we'll use Coverlet to generate code coverage metrics when we run our tests and use ReportGenerator to show us the results.
-
Add the
Coverlet.MSBuildNuGet package to the both projects.dotnet add package coverlet.msbuild
-
Install the
ReportGeneratortool:dotnet tool install -g dotnet-reportgenerator-globaltool
-
Run the tests and collect coverage using the dotnet test command with an absolute path.
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput="$(pwd)/coverage/"
-
Run the
ReportGeneratortool:dotnet reportgenerator "-reports:HelloWorld.Tests/coverage.opencover.xml" "-targetdir:coveragereport" "-reporttypes:Html"
Amazing, ๐ฏ% code coverage!
Pro Tip: If it doesn't generate coverage.opencover.xml, you've successfully reproduced my results. Somethings broken and needs fixing. Good luck!
Congratulations, you're a real Software Engineer now!
Problem 3: Retaining some dignity
Technically, (nobody cares, but...) public is bad. Okay, so is chasing ๐ฏ% code coverage. But it's ONE LINE of code, so 100% isn't crazy!
Anyway, since public compromised encapsulation and security, we should really make them both internal, and give exclusive access only to our tests.
Applying some compiler wizardry ๐งโโ๏ธ in an AssemblyInfo.cs, we specify InternalsVisibleTo to make it so.
[assembly: InternalsVisibleTo("HelloWorld.Tests")]Problem Solved! But adding AssemblyInfo.cs has really screwed up our 1-liner and dropped the code coverage below ๐ฏ%. Inconceivable!
Problem 4: Achieving 100% test coverage
Ironically, adding AssemblyInfo.cs to facillitate testing the code to ๐ฏ%, adds a bit of code we can't bloody test!
This impacts the code coverage, so we exclude that from code coverage.
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[HelloWorldCSharp]*AssemblyInfo.cs"Conclusion
Much of this sillyness can be avoided, by:
- Creating an
internalHelloWorld class - Not chasing minimalism and ๐ฏ% code coverage
- Buy a Visual Studio Enterprise license
Technically, Main is the entrypoint of Program, so testing it is technically an End-to-End test anyway!
Of course, all of this is inconceviable! for a Hello World app and all of this is very VERY silly.
If you don't like sillyness, probably don't write code. It's sillyness all the way down!




