Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Simulate" command line argument in unit-tests

I have some functionality, which depends on command line arguments, and different arguments should lead to different results.

I can't directly "simulate" this arguments, since there are some sort of chain dependencies - I need to unit-test some xaml control, which depends on view-model, which depends on certain additional class, which fetches command line arguments using Environment.GetCommandLineArgs, and I can't directly impact on this last class to set arguments manually instead of using GetCommandLineArgs.

So, I'd like to know, is there any way to make Environment.GetCommandLineArgs return value I want it to return, for certain unit-test.

like image 625
lentinant Avatar asked Apr 14 '16 14:04

lentinant


People also ask

Is it possible to pass command line arguments to a test?

It is possible to pass custom command line arguments to the test module.

How do I run an argument from the command line?

option. You can test command line arguments by running an executable from the "Command Prompt" in Windows or from the "DOS prompt" in older versions of Windows. You can also use command line arguments in program shortcuts, or when running an application by using Start -> Run.

Is it possible to pass command line arguments to a test execution in Junit?

Yes, We can pass command line arguments to a test execution by using -D JVM command-line options as shown below.

What is ARG command?

Description. The ARG( ) function returns the string value of one of the arguments specified in the operating system command that launched the session. The numeric expression position indicates which argument is to be returned.


2 Answers

You need to abstract Environment.GetCommandLineArgs or what ever is eventually calling it behind something you can mock

public interface ICommandLineInterface {
    string[] GetCommandLineArgs();
}

Which can eventually be implemented in a concrete class like

public class CommandInterface : ICommandLineInterface {
    public string[] GetCommandLineArgs() {
        return Environment.GetCommandLineArgs();
    }
}

And can be Tested using Moq and FluentAssertions

[TestMethod]
public void Test_Should_Simulate_Command_Line_Argument() {
    // Arrange
    string[] expectedArgs = new[] { "Hello", "World", "Fake", "Args" };
    var mockedCLI = new Mock<ICommandLineInterface>();
    mockedCLI.Setup(m => m.GetCommandLineArgs()).Returns(expectedArgs);
    var target = mockedCLI.Object;

    // Act
    var args = target.GetCommandLineArgs();

    // Assert
    args.Should().NotBeNull();
    args.Should().ContainInOrder(expectedArgs);

}
like image 131
Nkosi Avatar answered Sep 29 '22 22:09

Nkosi


Since you are dealing with environment variables, why don't we wrap the outside dependencies into one EnvironmentHelper class, then inject the dependencies?

Here is my suggestion:

public class EnvironmentHelper
{
    Func<string[]> getEnvironmentCommandLineArgs; 

       // other dependency injections can be placed here

       public EnvironmentHelper(Func<string[]> getEnvironmentCommandLineArgs)
       {
            this.getEnvironmentCommandLineArgs = getEnvironmentCommandLineArgs;
       }

       public string[] GetEnvironmentCommandLineArgs()
       {
            return getEnvironmentCommandLineArgs();
       }
}

Here is the Mock method:

public static string[] GetFakeEnvironmentCommandLineArgs()
{
    return new string[] { "arg1", "arg2" };
}

In your source code:

EnvironmentHelper envHelper = new EnvironmentHelper(Environment.GetCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();

In your unit test code:

EnvironmentHelper envHelper = new EnvironmentHelper(GetFakeEnvironmentCommandLineArgs);
string[] myArgs = envHelper.GetEnvironmentCommandLineArgs();
like image 37
Jian Huang Avatar answered Sep 29 '22 20:09

Jian Huang