views:

499

answers:

2

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?

A: 

one option is to use Win32 FindWindow to search for the new app opened window.

Mladen Prajdic
+3  A: 

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 );
      ...
 }
tvanfosson
Nice!... I overlooked the startInfo separation part... have to get my head around mocking some more... Thanks!
chakrit