Hi,
I have been looking for a way how to perform Unit test on .gh files with my on scripts. These scripts contains my custom components which were coded with C# in visual studio. I have created my own plugin. If I run that script in Rhino it works perfectly.
I tried to dig into unit testing of that .gh files with my components. I started with this repo which I was able to replicate and successfully run. However, If I modify .gh file to use my components and unit test to insert data to a parameter and recompute some of my components it fails. After some investigation I found out few problems which may or may not occurre:
- If I run more then one class with unit tests at once it fails during disposing grasshopper assembly (happens sometimes, few cases)
- If I run more then one class with unit tests at once it fails and throw error during redrawing rhino active doc. (I understand that rhino is open in headless mode and active doc == null, my code in the plugin is not ready for this option) (happens sometimes, few cases)
- If I run only one class with one test it works. However when, compute my custom component which should produce my own class as a output it do so but some of the output class properties are not correctly set or calculated. That cause some problems in the downstream objects and test result is fail. (happens every time). However, on default components (circle, line, etc.) it works smoothly.
Last issue is most challenging and the worst as it prevents me from using further using of unit tests.
I have also read many of the topics regarding unit testing at this forum. Unfortunately, non of it solve my problem. There are some topics, regarding similar problems.
I have also found there is a few more test repos
tmakin/RhinoCommonUnitTesting: Example of unit testing RhinoCommon from within the Visual Studio test runner on windows (github.com)
and
mcneel/Rhino.Testing: NUnit dotnet unit testing for Rhino3D (github.com)
which I am not sure if they are compatible with Rhino 7 and can run .gh files and test them.
So my questions are:
- Can I use unit tests with .gh file and custom components?
- Why only part of output data are computed correctly?
- Is it possible to run many unit test on multiple .gh files?
- What is the best option to preform such unit test with .gh files?
Many thanks for you time and reply. Any help is much appreciated.
Best Ondřej
Code of my unit tests:
public class CenterLineFixture : Rhino.Test.GrasshopperFixture
{
public CenterLineFixture() : base("CenterLine.gh") { }
}
public class CenterLine : IClassFixture<CenterLineFixture>
{
CenterLineFixture fixture { get; set; }
public CenterLine(CenterLineFixture fixture)
{
this.fixture = fixture;
}
/// This test works.
[Fact]
public void CircleTest()
{
List<double> doubles = new List<double>() { 1, 2, 3, 4, 5 };
foreach (var obj in (fixture.Doc.Objects))
{
if (obj is Grasshopper.Kernel.IGH_Param param)
{
if (param.NickName == "Radii")
{
for (var i = 0; i < doubles.Count; i++)
{
(param as Grasshopper.Kernel.Parameters.Param_Number).AddVolatileData(new Grasshopper.Kernel.Data.GH_Path(0), i, doubles[i]);
}
param.CollectData();
param.ComputeData();
Assert.Equal(doubles.Count, param.VolatileData.DataCount);
}
}
}
foreach (var obj in (fixture.Doc.Objects))
{
if (obj is Grasshopper.Kernel.IGH_Param param)
{
if (param.NickName == "Circle")
{
param.CollectData();
param.ComputeData();
Assert.Equal(doubles.Count, param.VolatileData.DataCount);
var data = param.VolatileData.AllData(true).GetEnumerator();
data.Reset();
int i = 0;
while (data.MoveNext())
{
var curve = data.Current;
Assert.True(curve.CastTo(out Curve curveToTest), "Cannot cast curve");
Assert.True(curveToTest.IsClosed, "Curve is not closed");
i++;
}
return;
}
}
}
}
/// This test does not work.
[Fact]
public void TunnelSectionTest()
{
foreach (var obj in (fixture.Doc.Objects))
{
if (obj is Grasshopper.Kernel.IGH_Component param)
{
/// Just get the custom component
if (param.NickName == "BoredSection")
{
/// Recompute custom component
param.ExpireSolution(true);
param.CollectData();
param.ComputeData();
/// Get output data of custom component. Output is custom class with properties. Some of them are not correctly computed.
object sectionClass = param.Params.Output.Last();
Assert.Equal(22, param.Params.Output.Count);
}
}
}
}
}