You have written some tests, now you try to run them and you get this exception:

jetbrains.mps.lang.test.runtime.ProjectPathIsNullException: The project path was not specified in the TestInfo root.

What’s going on and how do you fix this?

Solution

Below I list the steps to take to set up TestInfo roots properly. I used MPS 2020.1 and the robot_Kaja sample project. The sample project comes without tests and a build file so I created a simple test model and a build file from scratch.

  1. In Preferences → Appearance & Behavior → General define a path variable named your.project.home, set it to the MPS project directory:

    Defining the path variable

  2. Create TestInfo roots in each model that contains tests. Set the project path to ${your.project.home}:

    TestInfo for robot_Kaja sample

  3. In your build script, define two folder macros:

    • your.project.home, set to the MPS project directory
    • mps.macro.your.project.home, set to $your.project.home

    Folder macros

That’s it, now you should be able to run the tests from Ant or from MPS without receiving any complaints about the project path not being set.

Why do I need all this?

The underlying issue is that MPS-specific tests (node tests and editor tests) need to run in the context of a running MPS instance with an open project. When running in-process from MPS the tests can piggyback on the running instance but when running from the command line the tests have to start MPS and open the necessary project themselves. The project has to contain the original test model since it is accessed directly by the tests.

The tests cannot deduce the location of the project to open, the location has to be provided to them explicitly.

This location has to depend on some sort of outside input variable: Ant property, JVM property, an environment property, or a path variable. When in MPS the most user-friendly option is a path variable. In Ant, however, the best option would be an Ant property. MPS tries to use the most user-friendly option in each case.

Ant runs MPS tests using plain JUnit but with a custom Runner implementation that starts MPS for each test. The runner (MpsTestsSuite class) will read the system properties that start with mps.macro. prefix, strip the prefix, and convert the property into a path variable for the started MPS instance.

How do these mps.macro.foo properties end up as system properties when JUnit is started? By default, Ant variables are not propagated to JUnit but the build language generator explicitly passes along any folder macros that start with mps.macro. to the <junit> task as system properties (without stripping the mps.macro. prefix). And this completes the entire chain.

Drawbacks

Besides the complexity, there is one additional drawback to this approach that you should know about: if you have multiple checkouts of the same project lying around and want to execute tests from MPS you will need to set the path variable to the project that you currently have open. Fortunately, MPS (as of 2020.1) will not try to do anything smart if you forget and will just throw an exception if the correct project isn’t currently open.

Additional resources

Read more about TestInfo here: