Tobi
Tobi

Reputation: 5519

Library working when called from Console app but not from NUnit test

I'm trying to evaluate a workflow library for a project I'm working on. The lib can be found at github workflow-core.

To start things up I was trying to build a simple workflow, that just writes some text to a file. The curious thing is, that the workflow works fine, when called from a console application project. But when I use the same code in an NUnit test and run it, it doesn't write anything to the file.

I'm a little lost here and don't even know which details are import for you guys to know to help me figure this out, but maybe this might be relevant?

And here is the relevant code: First the workflow class:

public class HelloWorldWorkflow : IWorkflow
{
    public string Id => nameof(HelloWorldWorkflow);
    public int Version => 1;
    public void Build(IWorkflowBuilder<object> builder)
    {
        builder.StartWith((context) =>
        {
            File.WriteAllText(@"C:\Test\test.txt", "Test line worked!");
            return ExecutionResult.Next();
        });
    }
}

The calling code from the console app (working):

class Program
{
    static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging((config) => config.AddConsole());
        serviceCollection.AddWorkflow();

        serviceCollection.AddTransient<LogStep>();

        var serviceProvider = serviceCollection.BuildServiceProvider();

        var host = serviceProvider.GetService<IWorkflowHost>();
        host.RegisterWorkflow<HelloWorldWorkflow>();

        host.Start();

        host.StartWorkflow(nameof(HelloWorldWorkflow));

        Console.WriteLine("Done");
        Console.ReadLine();

        host.Stop();
    }
}

And the code from my test project (not working):

[TestFixture]
public class ExplorationTests
{
    private ServiceProvider _serviceProvider;
    private IWorkflowHost _host;

    [OneTimeSetUp]
    public void Init()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddLogging((config) => config.AddConsole());
        serviceCollection.AddWorkflow();

        serviceCollection.AddTransient<LogStep>();
        serviceCollection.AddTransient<HelloWorldWorkflow>();

        _serviceProvider = serviceCollection.BuildServiceProvider();

        _host = _serviceProvider.GetService<IWorkflowHost>();
        _host.RegisterWorkflow<HelloWorldWorkflow>();

        _host.Start();
    }

    [Test]
    public void Test()
    {
        _host.StartWorkflow(nameof(HelloWorldWorkflow));

    }

    [OneTimeTearDown]
    public void TearDown()
    {
        _host.Stop();
    }
}

I'd be glad for any clues on how to figure this out.

Upvotes: 0

Views: 653

Answers (3)

Hero Wanders
Hero Wanders

Reputation: 3292

Execution of workflows is asynchronous, therefore you have to wait for some kind of event to occur which signals the completion. Otherwise your test teardown will kill the host before the workflow has the chance to do anything.

This answer's first version contained:

Adding .Wait() or one of its overloadings (which allow to specify a maximum duration to wait) to the result of StartWorkflow to block the test until the workflow has completed.

Unfortunately that's wrong as StartWorkflow returns a Task yielding only the ID of the workflow instance. When this task is resolved your workflow probably hasn't done anything meaningful.

There is a feature request on GitHub asking for the desired feature: Wait for workflow to finish

Until that request is resolved, you may help yourself by creating a ManualResetEvent or maybe AutoResetEvent and putting it somewhere your final workflow step can access and call .Set() on it. Your test should wait for that by calling .WaitOne() on it (this is blocking).

Another event which might be sufficient (but inefficient) is just having waited a long enough duration: Thread.Sleep(2000) waits two seconds. Please be aware that even after that it's possible that your workflow has not completed due to the asynchronous nature of the workflow executor.

Upvotes: 1

Charlie
Charlie

Reputation: 13736

It looks like your test starts a task running in the host and then exits without waiting for completion. The one time teardown would then run immediately and stop the host.

You should not be ending the test without waiting for the task to complete.

Upvotes: 0

Nilesh Shinde
Nilesh Shinde

Reputation: 392

Can you try by making 'var serviceCollection' as class member of ExplorationTests. Otherwise code looks ok.

Upvotes: 0

Related Questions