Orleans TestClusterBuilder can't share dependency injection registrations
Asked Answered
L

1

8

I can't figure out how to share my service registrations between my test code that uses Orleans and the test code that is outside of Orleans. I've spent days trying to figure this out.

My unit tests have their own ServiceCollection where I've registered the services that my application requires. For my experiment, I'm registering one singleton (Something).

I'm now adding Orleans' TestClusterBuilder to my unit test. According to the docs, I need to AddSiloBuilderConfigurator....

How do I avoid registering Something twice? This feels like a chicken-and-egg situation. Worse still, the Something that gets injected in my grains is a different singleton than the Something that gets registered in app.

This only seems to be a problem in my unit tests. In the main application code, there is no TestClusterBuilder and the DI works as expected.

My code looks something like:

[SetUp]
public void Setup()
{
    var webApplicationBuilder = WebApplication.CreateBuilder();
    webApplicationBuilder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureContainer<ContainerBuilder>(c =>
        {
            c.RegisterType<Something>().AsSelf().SingleInstance();
        });


    var app = webApplicationBuilder.Build();

    var testClusterBuilder = new TestClusterBuilder(1);
    testClusterBuilder.AddSiloBuilderConfigurator<TestSiloConfigurations>();
    TestCluster = testClusterBuilder.Build();
    TestCluster.Deploy();
}

public class TestSiloConfigurations : ISiloConfigurator
{
    public void Configure(ISiloBuilder siloBuilder)
    {
        siloBuilder.ConfigureServices(services =>
        {
            services.AddSingleton<Something>();
        });
    }
}

For the record, we're using Autofac, but I don't think that matters here.

Lutist answered 4/12, 2023 at 20:21 Comment(1)
I am not familiar with .NET or Orleans but it seems like the TestCluster is a DI enabled environment with some sort of container for storing .NET class instances when running your application. If you are configuring services in the TestSiloConfigurations class to make them available to other tests, why not move the app builder and app into the siloBuilder where you add your Something singleton, and then access the app via the silo?Depilatory
M
0

The TestClusterBuilder will result to run multiple silo in respective AppDomaine to simulate multiple servers. So no data nor service share.

I found a solution by creating a Remote Service through Named Pipe.

Basically each silo have a client that call a remote service where i can monitor the behavior during my test or expose shared data.

Link to implementation code : https://github.com/Nexai-net/democrite/tree/main/src/Tests/Democrite.UnitTests.ToolKit/Remoting

Example for unit test : https://github.com/Nexai-net/democrite/blob/v0.4.3-beta/src/Tests/Democrite.Framework.Node.UnitTests/SequenceExecutorUnitTest.cs Line: 366

You will also found their an example to setup a grain correctly to test it like in MS Orleans environment. Usefull to test individually without to setup a full silo context.

https://github.com/Nexai-net/democrite/blob/main/src/Tests/Democrite.UnitTests.ToolKit/Extensions/AutoFixtureExtensions.cs

Methylnaphthalene answered 23/8 at 13:57 Comment(1)
Interesting! This is a lot to take in, so I don't yet understand everything I'm looking at. I was able to come up with a solution, but I forgot to update this page with my code. I'll try to get around to that this week, and also look what you've posted here. Using named pipes feels a bit out of place, and I also see that you're using reflection. But maybe your way is the best way.Lutist

© 2022 - 2024 — McMap. All rights reserved.