Is it possible to have multiple source roots in unit tests?

Answered

In the plugin I'm developing, I need to verify that my custom action is available only in the test JVM source root (JavaSourceRootType.TEST_SOURCE).

By default, the LightProjectDescritor in the LightJavaCodeInsightFixtureTestCase will create the temp:///src directory and mark it as a source root.

For my test to be as close to reality as possible, I wanted to create two - a src/main/java source root and a src/test/groovy test source root.

The test would then verify that the action is available in one but not in the other source root.

I am not sure whether this is even possible. The LightTempDirTestFixtureImpl relies on a single source root only. I can override the LightProjectDescritor, LightTempDirTestFixtureImpl and create a custom IdeaTestExecutionPolicy, but this seems a bit complicated and I am not sure if this is the right way to go.

Also, I am not sure where is the right place to register my source roots and how to create them. The LightProjectDescriptor#createSourceRoot only seems to accept a directory name rather than a path.

0
5 comments

You can simply add test sources directory programmatically in the specific test

VirtualFile testRootDir = myFixture.getTempDirFixture().findOrCreateDir("testRoot");
PsiTestUtil.addSourceRoot(getModule(), testRootDir, true);
Disposer.register(myFixture.getTestRootDisposable(), () -> PsiTestUtil.removeSourceRoot(getModule(), testRootDir));

 

Or provide custom LightProjectDescriptor and override configureModule()

0

Thanks Yann Cebron for the hints!

I aim to do this setup for all tests, so the LightProjectDescriptor will be the way to go.

There is one catch though. I wanted the new SpockLightProjectDescriptor to be a standalone class, so I added the fixture as a constructor parameter.

However, there is a circular dependency now

  1. The SpockLightProjectDescriptor needs myFixture but myFixture is null until the LightProjectDescriptor.setup() is called. 
  2. The LightProjectDescriptor.setup() calls getProjectDescriptor().

I can workaround it of course, but I was wondering if I could do all the stuff in the SpockLightProjectDescriptor without the fixture.

  1. Creating a virtual folder and adding it to source roots is easy.
  2. Getting hold of myFixture.testRootDisposable would mean calling an internal API (module.project as ProjectEx).earlyDisposable).

When I commented out the suggested Disposer.register(myFixture.getTestRootDisposable(), () -> PsiTestUtil.removeSourceRoot(getModule(), testRootDir)); code, I thought that meant the source root wouldn't be removed after every test. However, each test seems to start fresh with only the temp://src directory setup.

0

There is another problem. If I follow your steps and create src/main/java , the action is available even though it's not in a real IntelliJ instance.

When debugging, the CreateTemplateInPackageAction#isAvailable() returns true in tests whereas in real instances it returns false when the action is run in the src/main/java directory.

Debugging more, the difference can be spotted in the attached pictures:

  1. Both in IntelliJ and the test the fileSet.root points to the src/main/java or src/main/kotlin. All good here.
  2. But fileSet.data.customContentRoot differ. For the test it's null but in IntelliJ, it points to src/main.

It seems like the test setup is not the same as in real IntelliJ.

0

Sorry, but it's quite impossible to understand and reproduce your issues without access to the full sources.

0

Yeah, I understand. The sources are here: https://github.com/lobodpav/spock-intellij-plugin

Replication steps:

  1. Checkout the https://github.com/lobodpav/spock-intellij-plugin/tree/problem/test-setup-multiple-source-roots branch.
  2. Run the io.github.lobodpav.spock.action.NewSpockSpecificationActionIdeaSpec#The action is available only when Groovy and Spock are on the classpath test.
  3. For the first 3 items in the data table, the test fails. For instance, the isAvailable method returns true  for main/java (which is incorrect and the action is unavailable in real IntelliJ).
0

Please sign in to leave a comment.