Unit Test code with static method Console.Write

tl;dr : Wrap theses methods inside the layer of abstraction. Then create a stub and use it to create test scenarios.

This post is based on my answer on the Stack Overflow – “How to unit test this function?”

The original question is about writing unit test for a code that uses Console methods inside its body. This problem is more general and in this post, I want to show one of the ways to unit test code with static method.

Example of code with static methods

This example is from the Stack Overflow question.

Little Explanation

Method GetMaskedInput() does two things.

  • Whenever your press a key it shows you a ‘*’ char
  • All the keys are also appended to the string and returned

It’s a simple implementation of the hidden input. Something like a password text box on login screens.

Whats wrong with static method ?

This sample method is highly dependant on the Console.ReadKey and Console.Write methods. Code like this is only usable when we have access to console. Running it in for instance web.app enviroment would be problematic. This is one of the reasons that static methods are evil. Not like famous “goto”, beacuse there are scenarios in which statics are ok.

  • extension methods
  • simple helpers with input, output contained in the scope of the function (no globals, external dependancies )

Use of static methods seems like an easier solution, but in the long run, code written like this becomes problematic. It’s simple, clear and easy, but when you want to write unit test there is a problem. You are not able to write correct unit test for it.

What’s the correct unit test ?

  • it has to test unit of work
  • contains only one assert
  • most important it is self contained

With static methods like Console.ReadKey and Console.Write you can’t do it. These methods are dependant on the Windows Console implementation. We can’t control this behaviour, we don’t know exactly how it works inside. What we can do is to get rid of them.

Getting rid of static method

In this approach, I will show you how to hide “static” methods behind a layer of abstraction. Instead of using Console methods directly, let us inject some class that uses Console.

New Method

Interface definition

The sample method now have one parameter. This parameter is an interface IConsoleWrapper that has two methods. Their name is similar to the methods provided by the console Class. New code now calls the IConsoleWrapper interface. It doesn’t need to know implementation details.

Interface implementation

The implementation of Console is now hidden. It was done by wrapping the static methods inside a class that can now be injected to the GetMaskedInput method.

We are able now to write unit test for the code.

Unit Test Example with Stub

In order to test this code, we can create a stub that implements the IConsoleWrapper interface. This stub will just simulate Console. We can control it’s behaviour and thus create a stable test scenarios.

Test Stub

This stub simulates Write method by maintaing the Output variable. It’s a string and calling Write now appends this Output. We can now check the Output easily in the unit test.

ReadKey method is simulated by returning predefined data provided through a stub constructor. This behaviour is similar to replaying a recorded message. For each test a new stub is created with predefined key collection. Each call to ReadKey returns next key from the collection.

Test

This test will simulate a scenario with user clicking A,B,Enter keys. Enter should finish the procedure. We are expecting to see two “*” chars in the output and “AB” should be returned. Test has two asserts so it’s not a perfect example, but this particular logic required us to do this.

Summary

  • static methods are evil get rid of them if you want to write unit test
  • do this by hiding them behind a layer of abstraction
  • write unit tests by mocking this layer or create a stub that simulates behaviour needed for the test
Share on Facebook+1Share on Twitter
  • anonymous

    You say “static methods are evil get rid of them if you want to write unit test” but Program.GetMaskedInput is still a static method.

    • MichalFranc

      Yep :) And you should also get rid of this function. In original question on SO it is not static. I made it like this here, just for test purposes.

  • macjedrzejewski

    I can agree with most of your post, but not with this:
    What’s the correct unit test ?
    contains only one assert
    There are a lot of situations in which you can not use only one assert. We should write one test for each method, but not assert. Furthermore, you have already used 2 asserts in your test – so I think, that this point is not correct – and you know it :)
    Kind regards,

    MJ

    • MichalFranc

      hey , tnx for this comment :) This test is not correct. Ideally i should split it into two separates tests. One checking the output. Second one checking the mask. Now i have an idea for another post :)

      Here is an example on how to fulfill one characteristic of correct unit test. Unit test is self contained and not dependant on external stuff.

  • Pingback: Good unit test - One Assert | Passionate Programmer

  • Pingback: Testowanie statycznych wywołań na przykładzie DateTime.Now | Maciej Aniserowicz o programowaniu