dotnet / orleans

Cloud Native application framework for .NET
https://docs.microsoft.com/dotnet/orleans
MIT License
10.07k stars 2.03k forks source link

Unit Testing in .net core #2846

Closed ZhaoXiangXML closed 7 years ago

ZhaoXiangXML commented 7 years ago

I'm trying to do unit testing of my Orleans project based on .net core 1.1.1

I'm following the link https://dotnet.github.io/orleans/Tutorials/Unit-Testing-Grains.html

So I created a "Unit Test Project (.NET Core)" and trying to add the packages with install-package Microsoft.Orleans.TestingHost -version 2.0.0-preview2-201703021703

It turns out this package is only available for .NET Framework.

I also tried to create a Unit Test Project of .NET Framework, however I can't add my .Net Core Grains project as reference.

So is there anything plan to publish a .Net Core version of the TestingHost?

ZhaoXiangXML commented 7 years ago

So I changed by Interfaces project and Grains project to .NET Standard, so they can be referenced by both .NET Core and .NET Framework.

I've a test class like this:

    public class LoginTest : IDisposable
    {
        private readonly ITestOutputHelper output;
        private TestCluster testCluster;

        public LoginTest(ITestOutputHelper output)
        {
            this.output = output;
        }

        private void Initialize(TestClusterOptions options = null)
        {
            if (options == null)
            {
                options = new TestClusterOptions(1);
            }
            testCluster = new TestCluster(options);
            testCluster.Deploy();
        }

        public void Dispose()
        {
            testCluster?.StopAllSilos();
            testCluster = null;
        }

        [Fact]
        public async Task TestConfig()
        {
            Initialize();

            var config = testCluster.GrainFactory.GetGrain<IConfig>(0);

            var minVersion = await config.GetConfigString("min_version", Protocol.Tunnel.AndroidGoogle);

            Assert.False(String.IsNullOrWhiteSpace(minVersion));
        }
    }

This works well in my Silo host project.

However the test throws an exception:

[xUnit.net 00:00:06.2567186]     GameServer.Test.LoginTest.TestConfig [FAIL]
[xUnit.net 00:00:06.2584991]       System.InvalidOperationException : Cannot find generated GrainReference class for interface 'GameServer.Interfaces.IConfig'
[xUnit.net 00:00:06.2596806]       Stack Trace:
[xUnit.net 00:00:06.2604280]            at Orleans.Runtime.TypeMetadataCache.GetGrainReferenceType(Type interfaceType)
[xUnit.net 00:00:06.2607663]            at Orleans.GrainFactory.MakeCaster(Type interfaceType)
[xUnit.net 00:00:06.2611327]            at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
[xUnit.net 00:00:06.2614081]            at Orleans.GrainFactory.Cast(IAddressable grain, Type interfaceType)
[xUnit.net 00:00:06.2617210]            at Orleans.GrainFactory.Cast[TGrainInterface](IAddressable grain)
[xUnit.net 00:00:06.2620233]            at Orleans.GrainFactory.GetGrain[TGrainInterface](Int64 primaryKey, String grainClassNamePrefix)
[xUnit.net 00:00:06.2622919]         C:\Projects\NBAPro\Server\GameServer.Test\LoginTest.cs(44,0): at GameServer.Test.LoginTest.<TestConfig>d__5.MoveNext()
[xUnit.net 00:00:06.2626051]         --- End of stack trace from previous location where exception was thrown ---
[xUnit.net 00:00:06.2629112]            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
[xUnit.net 00:00:06.2632261]            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[xUnit.net 00:00:06.2634880]         --- End of stack trace from previous location where exception was thrown ---
[xUnit.net 00:00:06.2637991]            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
[xUnit.net 00:00:06.2640725]            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[xUnit.net 00:00:06.2642712]         --- End of stack trace from previous location where exception was thrown ---
[xUnit.net 00:00:06.2645152]            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
[xUnit.net 00:00:06.2647154]            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[xUnit.net 00:00:06.2824949]   Finished:    GameServer.Test

It appears the implementation of my grain interface is not found. I'm sure I've referenced the project.

jdom commented 7 years ago

Hi @ZhaoXiangXML, the TestHost package is indeed not available for .NET Core yet, since we rely on spinning up new AppDomains to run multiple silos in isolation. We will probably start supporting it soon, since we did a lot of work to reduce the usage of statics, so in theory we are not far from being able to start multiple silos in the main context.

We ourselves are doing the same thing as you, to at least test the domain logic by making the grain projects .NET Standard, but hosting the tests in full .NET.

The error you see there might be because you might not be using neither runtime nor build time codegen. Are you referencing OrleansCodeGenerator.Build in your grain projects, or OrleansCodeGenerator in your test project? (you shouldn't need both, just 1 of the 2 alternatives, although it doesn't hurt to have both either)

ZhaoXiangXML commented 7 years ago

Thanks @jdom, I added the generator in my test project, and now it works.