• 20 hours
  • Easy

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 6/17/24

Test that a function does what it says

The role of testing

Programming is generating code that works as intended. We've previously dealt with errors (such as compilation) that needed to be fixed while writing, as well as some during runtime. Let's go deeper to ensure that your functions work correctly and as planned. To do that, you need to test your code.

There are two categories of ways that you can test your functions:

  1. Using helping code.

  2. Using automated processes.

Testing using helping code

Helping code is a set of functions designed to test your main functions within the application. For example, if you have a class that does simple math, you could define something like this:

class MagicMath
{
	public static int Sum(int a, int b)
	{
		return a + b;
	}

	public static int Sub(int a, int b)
	{
		return a - b;
	}
}

Then you could write some code to test it:

// Test Sum
if (MagicMath.Sum(1, 5) == 6)
{
    Console.WriteLine("Sum works Ok");
}
else
{
   Console.WriteLine("Sum doesn't work");
}

// Test Sub
if (MagicMath.Sub(10, 8) == 2)
{
   Console.WriteLine("Sub works Ok");
}
else
{
   Console.WriteLine("Sub doesn't work");
}

This looks like passable code - you'll should get correct results. Now let's imagine (only imagine 🙂) that you made a mistake in the class functions implementation, and swapped the numbers a and b:

class MagicMath
{
   public static int Sum(int a, int b)
   {
      return b + a;
   }

   public static int Sub(int a, int b)
   {
      return b - a;
   }
}

And run the same tests:

// Test Sum
if (MagicMath.Sum(1, 5) == 6)
{
   Console.WriteLine("Sum works Ok");
}
else
{
   Console.WriteLine("Sum doesn't work");
}

// Test Sub
if (MagicMath.Sub(10, 8) == 2)
{
   Console.WriteLine("Sub works Ok");
}
else
{
   Console.WriteLine("Sub doesn't work");
}

In this situation, the Sum function will remain unaffected - it makes no difference if you perform a + b or b + a.

But the Sub function will generate a completely incorrect result! 😱

In most cases, you'll have more sophisticated functionality within the functions that you have to test, but even with this simple example, you can see that it's easy to make a mistake and that it requires testing for multiple variations to spot an error.

In fact, simple mistakes are easier to make when you are sure you got it right. Here's a plausible scenario: you wrote your Sum with a mistake - b + a instead of a + b. You tested it and it worked just fine! Then you copied the code of the Sum function, replaced + with - and went on with your development without testing it. You were so sure it would work because the only difference between the two new functions is the math operator. Well, not always. That's why it's extremely important to test - whichever method you apply!

Formatting the helping code

Here you are creating some code that won't be utilized by users during the normal flow of the application. Therefore, it's best to separate this code from the main code. One way to do this is by dedicating a section within a class to test. That way, it can easily be spotted and removed.

Another way is to separate the helper test code into dedicated files so they can be spotted and removed. Make sure your test code is easily identifiable. For that, you can use words that are naturally associated, such as test, tmp, dummy, etc. Using the math example, you could organize the test code in functions:

public static void TestSum()
{
	if (MagicMath.Sum(1, 5) == 6)
	{
		Console.WriteLine("Sum works Ok");
	}
	else
	{
		Console.WriteLine("Sum doesn't work");
	}
}

public static void TestSub()
{
	if (MagicMath.Sub(10, 8) == 2)
	{
		Console.WriteLine("Sub works Ok");
	}
	else
	{
		Console.WriteLine("Sub doesn't work");
	}
}

And then simply call the test functions:

// Test Sum
MagicMath.TestSum();
// Test Sub
MagicMath.TestSub();

This approach is useful in many cases; however, as the complexity of your project grows, these methods become less reliable and more time-consuming. You can take the idea of separating the test code further and transform it into a test application altogether. That brings us to the next subtopic: automated processes.

Testing using automated processes

Testing can be more efficient using automated processes. Dedicated tools enable you to create a test layer, which is a whole new application that tests the main application. The test application works in tandem with the main application ensuring that your program logic functions as expected.

There are two categories of application testing:

  • Functional testing

  • Unit testing

Functional tests can be programmatic (automated) or strategic (manual), and are used to test a complete feature of an application.

Unit tests are programmatic tests used to validate a small piece of code, typically a method or function. Similar to the helping code earlier in this chapter, except formatted and isolated into a separate application. There are, however, two characteristic differences.

The first one is uses precise naming techniques that spell out the exact conditions. In this case, the arguments you test. That would transform your test function names to:

// test Sum
public void TestOnePlusFiveEqualsSix()
{
}

// test Sub
public void TestTenMinusEightEqualsTwo()
{
}

Here, you will also notice that you no longer need to use Sum or Sub when naming a test function because you have very specific, spelled out names that include Plus or Minus instead.

The second difference is that rather than printing output as feedback, the function would throw an exception and generate an error on purpose. In C#, you can use methods that are prewritten, so instead of reinventing the wheel, you can add the library with all of the methods and variables associated with it.

Remember, writing tests is always a good idea! 🏆

Try it out for yourself!

Ready to get started? To access the exercise, click this link.

Let's recap!

In this chapter, you learned an important part of programming: testing, which has two categories:

  • Using helper code.

    • Testing helper code is implemented as a temporary code within the main application.

    • This approach is less reliable and works for quick tests in smaller projects.

  • Using automated processes that utilize dedicated tools.

    • Unit testing is a popular example of automated testing.

    • Automated testing is implemented as another application that tests the main application.

    • The main application and the test application work in tandem and mutually validate each other.

Example of certificate of achievement
Example of certificate of achievement