Unit testing C# Project

Hey, I am trying to start adding Unit Tests to my plugin Solution, but I am running into some issues I don’t know how to resolve.

I am trying to somewhat follow along with this tutorial, but I am not sure how to get rhinocommon in the Testing Project.

I tried using NuGet to add rhinocommon but the .NET frameworks are not compatible.


I have .NET Framework 4.8 installed, but it doesn’t show up in my Target framework list for this project. It shows up correctly in my plugin’s project.

I found someone with a similar .NET framework issue on this forum post. It looks like they had to change the type of project to expose the right framework options. I am not sure how to do something like this for the testing project template.

Since I am linking a bunch of stuff that I have found helpful so far, here is one project that actually has unit tests working. I cloned the project, built it, and ran the tests. It worked great, but I can’t figure out how they added the Rhino dependency. I am guessing they are not using NuGet, or setting up their test project from a different template…

Any help would be greatly appreciated. I couldn’t find a post on here that details how to get started with unit testing.

Update - still not really working, but I can run tests using rhinocommon. Now I am having trouble calling methods from my Plugin Project from within this Solution.

To get to this point, I copied the testing project out of the cloned example project. Then added it to my solution as an existing project. I then added my plugin project as a project dependency.

I made two simple tests. One just gets the dot product of two vectors from Vector3. This worked fine. The second test calls an example method from my plugin solution that gives the angle between two vectors. Here’s the error message:

System.IO.FileNotFoundException: Could not load file or assembly ‘rsgh, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

I think this is very close, but I am not sure why the file can’t be found. I will keep digging and post an update when things progress in either direction.

Here’s a sample we wrote with respect to unit tests and grasshopper.

You want to use the Rhino.Inside nuget package in order to create unit tests as that will load Rhino as a library inside of the unit testing framework.

4 Likes

Awesome! I will dig into this, and see if I can get things working. Thanks for the help.

@stevebaer, I added the linked GrasshopperTests project into my solution and added my plugin project as a project reference to GrasshopperTests, but I seem to be getting the same Error Message:

System.IO.FileNotFoundException : Could not load file or assembly ‘rsgh, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

rsgh is the name of my plugin project. Is there some other way to point the test project at my plugin project?

Maybe I am misunderstanding how this test file is supposed to work.

I am adding a using statement to include my plugin project’s namespace, then adding a new test method that calls a method from my plugin project.

    [Fact]
    public void TestRSGH()
    {
            Assert.True(rs_gh.GetAngle(Vector3d.XAxis, Vector3d.YAxis) == 90.0);
    }

It looks like the example tests are using a grasshopper file as a fixture and looking at the resulting values of Doc.Objects. Do I need to make a grasshopper file, add it to my testing project, make the file.gh a fixture and assert on the values of params in the document?

Ok, I tested adding my component to the grasshopper file, naming the output param, made a new test method, and got the test to work.

This is helpful, but I still don’t know how to test individual methods from within my plugin project. My plugin has many methods that help to create a few components. Is there any way to test these methods without making a component for each one?

I am also not sure how I can test my non-native types. If I have a component output generic data that is a type from my plugin project, how would I cast the object to my object type for testing? I think I would still need to get the project reference working so the testing project would have access to the customs objects.

@Bill_Cook wrote this sample. Bill can you help with these questions?

There is also the Rhino3dm Nuget package, which doesn’t require Rhino to be installed and targets NET Standard 2.0. Using this rather than Rhinocommon in your test project has other benefits, like you can run test on linux for CI/CD, and use dotnet 6.0.

The disadvantage is that not all Rhinocommon functionality is available in Rhino3dm, so it depends on what you are testing.

I’m PTO today but will attempt to get to it this evening

@Dani_Abalde, thank you for the link. I was looking through your github earlier and it looks like a nice way to make unit tests in grasshopper. Is there a way to test the underlying code as well? I would like to make unit tests that have more coverage than just the resulting definitions.

Is there any way to make my grasshopper plugin compile into a dll like a normal C# Class Library would?
If I am not mistaken, this would make it so that I could make traditional unit tests for the objects in my project. Right now, I can’t link my testing project to my plugin project, and I think this is because there is not plugin.dll.

I am thinking that I might need to split the business logic out of my plugin’s project. If I put the logic in a project that compiles to a dll, I could reference it in my plugin project and reference it in my test project. I am not sure if this is necessary, but I can’t think of another solution if I can’t reference my plugin project to my testing project.

There is a readme.txt file in the test sample which describes how to do this. :

Notes:

(1) The Visual Studio XUnit template wizard only includes options for .Net Core projects. After creating your XUnit test project, you must
	right-click on the project in SOlution Explorer and select 'Edit Project File'. You will see a couple of lines near the top that look
	like this:

		<PropertyGroup>
			<TargetFramework>net5.0</TargetFramework>

	Change "net5.0" to "net48" for Rhino7 tests.

(2) You need to set the project platform to "x64"

(3) You must include a file called "xunit.runner.json" to configure XUnit to NOT use AppDomains. You should also set XUnit not to 
	parallelize the tests. You can do this by adding a text file to the project with that name, and it should look like this:

		{
			"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
			"appDomain": "denied"
			"parallelizeAssembly": false,
			"parallelizeTestCollections": false
		}

	Additional xunit options may be added (see https://xunit.net/docs/configuration-files). You must also ensure that this file is copied
	to your project output directory. Select xunit.runner.json in solution explorer and select 'Copy if newer'
 
(4) You must add Rhino.Inside to your test project using NuGet

(5) This example also uses the same mechanism as in (3) to copy relevant grassopper files into the output directory, but you can use a hard-coded
	path if you chose.

This particular sample was written for the purpose of testing grasshopper components, and should work for you if I understand correctly what you are trying to do. It uses Rhino.Inside to load a headless instance of grasshopper and test grasshopper components using test GH files.

1 Like