Rhino.Testing

Hello dear colleagues,

I have recently came to conclusion that I need to do a unit tests to my GH plugin. Searching this forum I have discovered few repos/packages which should be suitable for this.

First idea was to test my GH scripts with C# custom components according to this sample. However, it did not worked well and I left that approach. Issues are described in here (1 and 2 ).

Finally, I have found Rhino.Testing library which looks very promising. There are also the SampleTests repo, which I downloaded. My aim now is to test my plugin in the following cases:

  • Test my methods which uses RhinoCommon library.
  • Read Geometry from Rhino and use it for test of my methods.
  • Call methods like Curve.CreateInterpolatedCurve() in my tests and use result for testing my methods.
  • Run GH script and read result according to Rhino.Testing workflow.

And here comes the issues. Over last two days I have tried to put Rhino.Testing library into operation unfortunately behavior of the test is unclear to me.

When I run the sample repo it works except tests when Rhino is opened (Headless or not; Net7.0 version works correctly). In these cases test are simply aborted, testing ends without any result. Test where Rhino.FileIO is used works just fine.

When I add new project to my plugin and set things according to instruction written here. it works only if I don’t use SetupFixture class.
So I can use Rhinocommon classes like Point3d etc. but I cannot use advanced methods like intersections and others. If I use them in test method I get error that rhcommon_c.dll cannot be referenced/found.

Using SetupFixture (according to the sample file and readme in the Rhino.Testing), which should solve this problem, as Rhino must be initialized for these advanced methods, leads to
different error. It occurs when OneTimeSetUp method is called. I have tried to reference RhinoCommon.dll for both Rhino 7 and Rhino 8 version. No change at all.

image

Class for the test is quite simple:

[TestFixture]
 public sealed class TestTunnel : RhinoTestFixture
 {
  [Test, Description("Test that constructor produce valid TBM_Class")]
     public void TestTunnelConstructor()
     {
         Assert.That(true);
     }
 }

Last try which I have done is simply adding SampleTests project to my solution. That works (again except tests where Rhino does not use Rhino.FileIO to read .3dm file). It works even if I reference different version of RhinoCommon.dll assembly in the tests project and my plugin. However, if I manually remove RhinoCommon.dll assembly reference from unit test project and add new one at the same location it stops to work and produce following error (System.DllNotFoundException: Liberary DLL RhinoLibraryCannot be found):

So my question is what I am missing/doing wrong? Why it works when I add sample repo but not for new one? What directory is not found? Why openHeadless method does not work for .Net48 version and work for .Net7.0?

Hope @fraguada or @menno could help me.

Thanks for the reply and time

Best regasrds

Ondřej

Just my own update. I was able to resolve problem with missing RhinoLibrary

and DirectoryNotFoundException.

I have mismatched copy local for some .dll and configs.xml file.

Now I have run into another (but minor issue). Which can be rather feature then problem. I would like to perform multiple testcases on one test. Some of the input to the tests is Rhino Geometry (curves, points etc). However, if I use TestCaseSource or TestCase attribute and define geometry in that input i again fails and raise error that RhinoCommon cannot be loaded.

    [TestFixture]
    public sealed class TestTunnel : RhinoTestFixture
    {
        private static IEnumerable<TestCaseData> TestTunnelConstructor_Params()
        {
            yield return new TestCaseData(null, null, Point3d.Unset, Point3d.Unset, false);
            yield return new TestCaseData(null, null, Point3d.Unset, Point3d.Unset, false);
            yield return new TestCaseData(null, null, new Point3d(0, 0, 0), Point3d.Unset, false);
            yield return new TestCaseData(null, null, new Point3d(0, 0, 0), new Point3d(1, 1, 1), false);
            yield return new TestCaseData(Curve.CreateInterpolatedCurve(new List<Point3d>() { new Point3d(0, 0, 0), new Point3d(1, 0, 0) }, 1), new List<Curve>(), new Point3d(0, 0, 0), new Point3d(1, 0, 0), true);
            yield return new TestCaseData(Curve.CreateInterpolatedCurve(new List<Point3d>() { new Point3d(0, 0, 0), new Point3d(1, 0, 0) }, 1), new List<Curve>(), new Point3d(0, 0, 0), new Point3d(1, 0, 0), true);
        }
        [Test, Description("Test of constructor produce valid TBM_Class")]
        [TestCaseSource(nameof(TestTunnelConstructor_Params))]
      
        public void TestTunnelConstructor(Curve alignment, List<Curve> alignments, Point3d startPoint, Point3d endPoint, bool result)
        {
            var tunnel = new TBM.TBM_Common.TBM_Tunnel(null, null, startPoint, endPoint);
            Assert.That(tunnel.IsValid == result);
        }

    }

If geometry is created directly in the test method it works. I except problem to be in the SetupFixuture class which (i assume) is not called before the input values (together with rhino geometry) are initialized. I am I right? Is this bug or feature I have to live with it? I can image some workaround (reading geometry from .3dm etc). But direct input with TestCaseSource would be much easier.

Thanks a lot for your reply and time.

Ondřej

I’ve followed along with this thread, and it sounds like things are mostly working for you now?

Regarding this;

The Rhino.Testing library inserts a resolver into the test classes that tell dotnet “Hey, if you can’t find an assembly, ask me! I might know where it is!”. Unfortunately, static C# properties load before this resolver is registered. Hence, it’s best if you use the [RhinoTestFixture] instead of inheriting the Test Setup class as attributes are created before static properties, and hence, allow that resolver to be registered before the static class can be instantiated.

Ssee docs here about this

1 Like

Thanks for your reply and advice. Most of the things now works. :smiley:

I have read the docs you mention, before I started to implement [Rhino.Testing]. However, If ‘[Rhino.Testing]’ library is installed via NuGet marking class [RhinoTestFixture] raises an error Cannot apply attribute class RhinoTestFixture because it is abstract. So, I left that option.
This happens for my my test and even for this sample.

When I look into Rhino.Testing repo itself [RhinoTestFixture] is used in some tests and works. Even if the attribute is [RhinoTestFixture] it points rather to the [RhinoTestFixtureAttrbute class] which is not marked as abstract.

I tried to add [Rhino.Testing] project to my solution and reference it as a project not via NuGet. And it works (stops to raise error with abstract class). So it looks like there is a difference between nuget version and a github and downloaded version.

Both says version 8.0.023.0

Am I missing something else?

Thanks

Ondřej

Would you be able to share your project, or a stripped down version @janotaondrej91, I’m trying to reproduce your issue, but I can’t seem to.