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>