I’m making C# libraries for Unity, doing TDD. Wrote some unit tests, currently running with NUnit directly (both in VS Code and Travis CI).
I can hook up UnityEngine.dll, it compiles well. But when I run the tests, it can’t find the methods during the test runtime.
Simple methods like Debug.Log, or JsonUtility.FromJson all fails with MissingMethodException:
System.MissingMethodException: Attempted to access a missing method.
at (wrapper managed-to-native) UnityEngine.JsonUtility:FromJson (string,System.Type)
at UnityEngine.JsonUtility.FromJson[T] (System.String json) [0x00001] in <ec28d45c6481407a9313eee207a323b3>:0
As I looked into UnityEngine.dll, I found that most of the methods are falling back to an external implementation, like JsonUtility.FromJson:
[GeneratedByOldBindingsGenerator, ThreadAndSerializationSafe]
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object FromJson(string json, Type type);
But I’d like to know how to provide those external implementations in a test runner.
Or am I just referencing the wrong dlls?
I’m using the ones located in /Applications/Unity/Unity.app/Contents/Managed.
But there are 7 other UnityEngine.dll files in the Unity.app bundle.
They’re directly wired into the Mono runtime (hence ‘InternalCall’) via the Mono embedding API. You’d need to be running your tests under a Mono runtime that wire up those InternalCalls - or just use the Mono runtime launched by Unity itself, by having Travis etc launch Unity and ask it to run your tests.
…but they are all throws the same MissingMethodException.
What Unity uses to run tests in the Editor?
Why I ask?
I just want to avoid, like… …switching back to Unity Editor every time I do some miiiiinnnor change in a library, then wait the entire project to be rebuilt, then run tests in Editor, then resolve a line number from the Inspector, then switch back to VS code, then lookup the error.
Compared to: run an NUnit task on a small library dll I just built, right in VS Code, within seconds.
Take a look at, for example, mono_marshal_init in marshal.c, line 195. That big sequence of 'register_icall` calls there is how the InternalCalls are registered with the Mono runtime.
At engine/editor startup, Unity’s C++ code makes calls similar to register_icall to wire up the InternalCalls you’re seeing in UnityEngine.dll. So when we’re executing managed code against our Mono instance, it has all the calls registered.
To my knowledge, there is no way to dynamically register an icall from managed code at runtime.
I there any chance to access the running mono instance of Unity Editor from command line? Having that I could make a VS Code task, by which I could run the tests within.
(on Travis CI speed is not a big concern, so I could go with using Unity.app command line directly there)
The Mono instance used by Unity is embedded inside the process - it is not a separate executable that can be launched independently. So yeah, you will need to launch Unity.app. We do have command-line parameters for activating the test runner, though.
Thanks, I came to the same conclusion.
Made a shell script that runs tests in batch mode.
#!/bin/sh
UNITY_EXECUTABLE="/Applications/Unity/Unity.app/Contents/MacOS/Unity"
PROJECT_FOLDER="/Users/eppz/Projects/Unity/Prototype/eppz"
RESULTS_FILENAME="eppz.Test.Result.xml"
echo "Run Unity.app (in batch mode) with editor test..."
time \
"$UNITY_EXECUTABLE" \
-batchmode \
-projectPath "$PROJECT_FOLDER" \
-runTests \
-testResults "$PROJECT_FOLDER/$RESULTS_FILENAME" \
-testPlatform editmode
I had difficulties while trying in 5.5.0, but it works nicely with 5.6.2f1.
It runs for ~18 sec even for a single test, but does the work (I can cut down 3 sec with -nographics).
Run Unity.app (in batch mode) with editor test...
real 0m18.193s
user 0m15.830s
sys 0m3.390s
Thanks again for pointing me to the right directions!
(and sorry for somewhat fragment your vacation)
Aw, this one actually prevents me to use this with VS Code (while the project is open).
“Opening a project in batch mode while the Editor has the same project open is not supported; only a single instance of Unity can run at a time.” - from Unity - Manual: Command-line arguments