Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Process.Start?

I am creating an application that will manage multiple instances of an external utility, supplying each with data and fetching results.

But as I am writing unit tests for the class I came upon a problem.

How do test that the target method actually starts a process (set via a property) when called?

I have tried:

  • Make the class execute an external process and then use GetProcessesByName to check if it has started.
  • Use output redirection, e.g. using the greater-than sign to echo something to a file and test its existence

I feel like emitting code and/or creating yet another exe to test is overkill.

This is the exact method:

public void Start()
{
    if (!_isRunning) {
        var startInfo = new ProcessStartInfo() {
            CreateNoWindow = true,
            UseShellExecute = true,

            FileName = _cmdLine,
            Arguments = _args
        };

        _process = Process.Start(startInfo);
        _isRunning = true;

    } else {
        throw new InvalidOperationException("Process already started");

    }
}

I want to unit-test it so that if nothing is running (_isRunning == false), a new process should be spawned.

I feel stumped, is there an elegant way to unit-test that an external process actually starts?

like image 724
chakrit Avatar asked Dec 08 '08 12:12

chakrit


People also ask

How does the testing process start?

Tests start at the unit level with developers performing unit tests. Then, the QA team runs tests at API and UI levels. Manual tests are run in accordance with previously designed test cases. All bugs detected are submitted in a defect tracking system.

What is process start?

Start(ProcessStartInfo)Starts the process resource that is specified by the parameter containing process start information (for example, the file name of the process to start) and associates the resource with a new Process component.

Which is the correct sequence of tests when testing new software?

There are four main stages of testing that need to be completed before a program can be cleared for use: unit testing, integration testing, system testing, and acceptance testing.


1 Answers

I would approach this using dependency injection and using a mock or fake class. Note I'm using the instance method for start instead of the class method. In your regular code, you can use the default constructor and it will create a process for you. For testing you can inject a mock or fake process and simply check that the proper methods are called on your mock object and never have to actually start a process at all. You'll need to adjust this to take account of the properties I've omitted. Ex. below:

 public class UtilityManager
 {
      public Process UtilityProcess { get; private set; }

      private bool _isRunning;

      public UtilityManager() : this(null) {}

      public UtilityManager( Process process )
      {
          this. UtilityProcess = process ?? new Process();
          this._isRunning = false;
      }

      public void Start()
      {
          if (!_isRunning) {
          var startInfo = new ProcessStartInfo() {
              CreateNoWindow = true,
              UseShellExecute = true,

              FileName = _cmdLine,
              Arguments = _args
          };

          this.UtilityProcess.Start(startInfo);
          _isRunning = true;

      } else {
          throw new InvalidOperationException("Process already started");
      }
 }

Test code...

 [TestMethod]
 public void StartTest()
 {
      Process proc = new FakeProcess();  // May need to use a wrapper class
      UtilityManager manager = new UtilityManager( proc );
      manager.CommandLine = "command";
      ...

      manager.Start();


      Assert.IsTrue( proc.StartCalled );
      Assert.IsNotNull( proc.StartInfo );
      Assert.AreEqual( "command", proc.StartInfo.FileName );
      ...
 }
like image 177
tvanfosson Avatar answered Oct 12 '22 01:10

tvanfosson