Tag Archives: Console Application

Manually Creating a Test Harness in .Net

Let me start by saying that this post isn’t intended to try to replace Selenium, or Cypress, or whatever UI testing tools you may choose to use. In fact, it’s something that I did for manual testing, although it’s not difficult to imagine introducing some minor automation.

The Problem

Imagine that you have a solution that requires some data – perhaps it requires a lot of data, because you’re testing some specific performance issue, or perhaps you just want to see what the screen looks like when you have a lot of data. Let’s also imagine that you’re repeatedly running your project for one reason or another, and adding data, or whatever.

My idea here was that I could create a C# application that scripts this process, but because it’s an internal application, I could give it access to the data layer directly.

The Solution

Basically, the solution to this (and to many things) was a console app. Let’s take a solution that implements a very basic service / repository pattern:

From this, we can see that we have a pretty standard layout, and essentially, what we’re trying to do is insert some data into the database. It’s a bonus if we can add some test coverage while we’re at it (manual test coverage is still test coverage – it just doesn’t show up on your stats). So, if you’re using a REST type pattern, you might want to use the controller endpoints to add the data; but for my purpose, I’m just going to add the data directly into the data access layer.

Let’s see what the console app looks like:

        static async Task Main(string[] args)
        {
            IConfiguration configuration = new ConfigurationBuilder()
                  .AddJsonFile("appsettings.json", true, true)
                  .Build();

            // Ensure the DB is populated
            var dataAccess = new TestDataAccess(configuration.GetConnectionString("ConnectionString"));
            if (dataAccess.GetDataCount() == 0)
            {
                var data = new List<MyData>();

	     // Generate 100 items of data
                for (int j = 0; j <= 100; j++)
                {
		var dataItem = CreateTestItem();
                      data.Add(dataItem);
                }
                dataAccess.AddDataRange(data);
            }

            // Launch the site            
            await RunCommand("dotnet", "build");
            await RunCommand("dotnet", "run", 5);

            System.Diagnostics.Process.Start(@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", @"https://localhost:5001");
        }

Okay, so let’s break this down: there’s essentially three sections to this: configuration, adding the data, and running the app.

Configuration

We’ll start with the configuration:

       IConfiguration configuration = new ConfigurationBuilder()
                  .AddJsonFile("appsettings.json", true, true)
                  .Build();

        // Ensure the DB is populated
        var dataAccess = new TestDataAccess(configuration.GetConnectionString("ConnectionString"));

Because we’re using a console app, we’ll need to get the configuration; you could copy the appsettings.json, but my suggestion would be to add a link; that is, add an existing item, and select that item from the main project, then choose to “Add As Link” (this is not a new feature):

This means that you’ll be able to change the config file, and it will be reflected in the test harness.

Creating the data

There’s not too much point in me covering what’s behind TestDataAccess – suffice to say that it encapsulates the data access layer; which, as a minimum, requires the connection string.

It’s also worth pointing out that we check whether there is any data there before running it. Depending on your specific use-case, you may choose to remove this.

Building, running, and launching the app

Okay, so we’ve now added our data, we now want to build the main application – thanks to the command line capabilities of .Net Core, this is much simpler than it was when we used to have to try and wrangle with MSBuild!

    // Launch the site            
    await RunCommand("dotnet", "build");
    await RunCommand("dotnet", "run", 5);

    await RunCommand(@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", @"https://localhost:5001");

RunCommand probably needs a little more attention, but before we look at that, let’s think about what we’re trying to do:

1. Build the application
2. When the application has built, run the application
3. Once the application is running, navigate to the site

RunCommand looks like this:

        private static async Task RunCommand(string command, string? args = null, int? waitSecs = -1)
        {
            Console.WriteLine($"Executing command: {command} (args: {args})");

            Process proc = new System.Diagnostics.Process();
            proc.StartInfo.WorkingDirectory = @"..\..\..\..\MyApp.App";
            proc.StartInfo.FileName = command;
            proc.StartInfo.Arguments = args ?? string.Empty;

            proc.Start();

            if ((waitSecs ?? -1) == -1)
            {
                proc.WaitForExit();
            }
            else
            {
                if (waitSecs! == 0) return;
                await Task.Delay(waitSecs!.Value * 1000);
            }
        }

“But this looks inordinately complicated for a simple wrapper for running a process!” I hear you say.

It is a bit, but the essence is this: when running the build command, we need to wait for it to complete, when running the run command, we can’t wait for it to complete, because it never will; but we do need to move to the next thing; and when we launch the site, we don’t really care whether it waits or not after that.

Summary

I appreciate that some of you may be regretting spending the time reading through this, as all I’ve essentially done is script some data creation and run an application; but I imagine there are some people out there, like me, that want to see (visually) what their app looks like with different data shapes.

Console Application Builds, But Will Not Run

While doing some testing recently, I created a new bog standard console application and, on pressing F5, nothing happened.

The project builds fine, but wouldn’t launch the console window.

Why (and how to fix)?

Well, I had installed the Azure Service Bus Client. Other than that, I can’t really say; however, the fix does kind of make sense:

Uncheck the “Prefer 32-bit” checkbox, and it all springs back to life!

Command-line start-up arguments that contain paths

Recently I was working on a console app; my start-up arguments looked like this:

CmdLineArgs

ArgumentOne “c:\tmp\” “c:\tmp2”

And I got an error with the following code:

string argumentone = args[0];
string sourceDir = args[1];
string destinationDir = args[2];

Turns out that the \” escapes the final quote of the second argument, and so the third line crashes because there were only two arguments. The fix is simple:

ArgumentOne “c:\tmp” “c:\tmp2”

Console Games – Catch – Part 1

I’ve written a series of posts based on teaching programming to children (specifically my 9 year old children). Currently, we’ve managed to produce a snake game, but we’re also working on a “Catch” game. This is a game whereby things drop from the top of the game screen, and the player must “Catch” them.

Before starting, it’s worth refering back to my first post for the basis of the game.

The initial set-up is the same; the difference for this game will mainly be that the player can only either move left, or right:

private static bool AcceptInput()
{
    if (!Console.KeyAvailable)
        return false;

    ConsoleKeyInfo key = Console.ReadKey();

    switch (key.Key)
    {
        case ConsoleKey.LeftArrow:
            _left--;
            break;
        case ConsoleKey.RightArrow:
            _left++;
            break;
    }

    return true;
}

Additionally, I’ve used a more bucket-like drawing for this game:

private static void DrawScreen()
{
    Console.Clear();
    Console.SetCursorPosition(_left, _top);
    Console.Write(@"\_/");
}

The main function and variables look like this still (the only change being the default for top, which should resolve to the height of the screen – 0, 0 being the top left):

private static int _left = 0;
private static int _top = Console.WindowHeight - 1;

static void Main(string[] args)
{
    Console.CursorVisible = false;
    DrawScreen();
    while (true)
    {
    if (AcceptInput())
    {
        DrawScreen();
    }
 }
 

So, now we have a basis, the “bucket” moves along the bottom of the screen. The next task is to introduce the “falling things”.