Tmds.ExecFunction is a library that makes it simple to execute a function in a separate process. This can be interesting for writing tests that require a separate process, or running some code with a different lifetime as the .NET application process. The library is based on the corefx RemoteExecutorTestBase class.
This library supports .NET Core 2.0 on Windows, Linux, and macOS.
The main method of the library is ExecFunction.Run
. It accepts a delegate that is the function to execute in the remote process. The function can have the same signature of a .NET Main
: a void
/string[]
argument, and a void
/int
/Task
/Task<int>
return type.
For example:
ExecFunction.Run(() => Console.WriteLine("Hello from child process!"));
The ProcessStartInfo
that is used to start the process can be configured, by adding a configuration delegate:
ExecFunction.Run(..., o => o.StartInfo.RedirectStandardOutput = true);
If you want to re-use the same configuration for multiple invocations you can use the FunctionExecutor
class.
private FunctionExecutor FunctionExecutor = new FunctionExecutor(o.StartInfo.RedirectStandardOutput = true);
// Now call FunctionExecutor.Run(...).
The configuration allows you to add an OnExit
action. For example, you can use this FunctionExecutor in an xunit project and Assert
in the child process:
private FunctionExecutor FunctionExecutor = new FunctionExecutor(
o =>
{
o.StartInfo.RedirectStandardError = true;
o.OnExit = p =>
{
if (p.ExitCode != 0)
{
string message = $"Function exit code failed with exit code: {p.ExitCode}" Environment.NewLine
p.StandardError.ReadToEnd();
throw new Xunit.Sdk.XunitException(message);
}
};
}
);
[Fact]
public void Test()
{
FunctionExecutor.Run(
(string[] args) =>
{
Assert.Equal("arg1", args[0]);
Assert.Equal("arg2", args[1]);
},
new string[] { "arg1", "arg2" }
);
}
When ExecFunction
is used from the dotnet
host, it will work out-of-the box.
To make ExecFunction
work from an application host (that is, when you've published your application as a native binary),
you need to add a hook in the main function:
static int Main(string[] args)
{
if (ExecFunction.IsExecFunctionCommand(args))
{
return ExecFunction.Program.Main(args);
}
else
{
ExecFunction.Run(() => System.Console.WriteLine("Hello world!"));
return 0;
}
}
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="tmds" value="https://www.myget.org/F/tmds/api/v3/index.json" />
</packageSources>
</configuration>