I have a piece of Java code which uses an environment variable and the behaviour of the code depends on the value of this variable. I would like to test this code with different values of the environment variable. How can I do this in JUnit?
I've seen some ways to set environment variables in Java in general, but I'm more interested in unit testing aspect of it, especially considering that tests shouldn't interfere with each other.
The library System Lambda has a method withEnvironmentVariable for setting environment variables.
import static com.github.stefanbirkner.systemlambda.SystemLambda.*;
public void EnvironmentVariablesTest {
#Test
public void setEnvironmentVariable() {
String value = withEnvironmentVariable("name", "value")
.execute(() -> System.getenv("name"));
assertEquals("value", value);
}
}
For Java 5 to 7 the library System Rules has a JUnit rule called EnvironmentVariables.
import org.junit.contrib.java.lang.system.EnvironmentVariables;
public class EnvironmentVariablesTest {
#Rule
public final EnvironmentVariables environmentVariables
= new EnvironmentVariables();
#Test
public void setEnvironmentVariable() {
environmentVariables.set("name", "value");
assertEquals("value", System.getenv("name"));
}
}
Full disclosure: I'm the author of both libraries.
The usual solution is to create a class which manages the access to this environmental variable, which you can then mock in your test class.
public class Environment {
public String getVariable() {
return System.getenv(); // or whatever
}
}
public class ServiceTest {
private static class MockEnvironment {
public String getVariable() {
return "foobar";
}
}
#Test public void testService() {
service.doSomething(new MockEnvironment());
}
}
The class under test then gets the environment variable using the Environment class, not directly from System.getenv().
In a similar situation like this where I had to write Test Case which is dependent on Environment Variable, I tried following:
I went for System Rules as suggested by Stefan Birkner. Its use was simple. But sooner than later, I found the behavior erratic. In one run, it works, in the very next run it fails. I investigated and found that System Rules work well with JUnit 4 or higher version. But in my cases, I was using some Jars which were dependent on JUnit 3. So I skipped System Rules. More on it you can find here #Rule annotation doesn't work while using TestSuite in JUnit.
Next I tried to create Environment Variable through Process Builder class provided by Java. Here through Java Code we can create an environment variable, but you need to know the process or program name which I did not. Also it creates environment variable for child process, not for the main process.
I wasted a day using the above two approaches, but of no avail. Then Maven came to my rescue. We can set Environment Variables or System Properties through Maven POM file which I think best way to do Unit Testing for Maven based project. Below is the entry I made in POM file.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<PropertyName1>PropertyValue1</PropertyName1>
<PropertyName2>PropertyValue2</PropertyName2>
</systemPropertyVariables>
<environmentVariables>
<EnvironmentVariable1>EnvironmentVariableValue1</EnvironmentVariable1>
<EnvironmentVariable2>EnvironmentVariableValue2</EnvironmentVariable2>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
After this change, I ran Test Cases again and suddenly all worked as expected. For reader's information, I explored this approach in Maven 3.x, so I have no idea on Maven 2.x.
I think the cleanest way to do this is with Mockito.spy(). It's a bit more lightweight than creating a separate class to mock and pass around.
Move your environment variable fetching to another method:
#VisibleForTesting
String getEnvironmentVariable(String envVar) {
return System.getenv(envVar);
}
Now in your unit test do this:
#Test
public void test() {
ClassToTest classToTest = new ClassToTest();
ClassToTest classToTestSpy = Mockito.spy(classToTest);
Mockito.when(classToTestSpy.getEnvironmentVariable("key")).thenReturn("value");
// Now test the method that uses getEnvironmentVariable
assertEquals("changedvalue", classToTestSpy.methodToTest());
}
For JUnit 4 users, System Lambda as suggested by Stefan Birkner is a great fit.
In case you are using JUnit 5, there is the JUnit Pioneer extension pack. It comes with #ClearEnvironmentVariable and #SetEnvironmentVariable. From the docs:
The #ClearEnvironmentVariable and #SetEnvironmentVariable annotations can be used to clear, respectively, set the values of environment variables for a test execution. Both annotations work on the test method and class level, are repeatable as well as combinable. After the annotated method has been executed, the variables mentioned in the annotation will be restored to their original value or will be cleared if they didn't have one before. Other environment variables that are changed during the test, are not restored.
Example:
#Test
#ClearEnvironmentVariable(key = "SOME_VARIABLE")
#SetEnvironmentVariable(key = "ANOTHER_VARIABLE", value = "new value")
void test() {
assertNull(System.getenv("SOME_VARIABLE"));
assertEquals("new value", System.getenv("ANOTHER_VARIABLE"));
}
I don't think this has been mentioned yet, but you could also use Powermockito:
Given:
package com.foo.service.impl;
public class FooServiceImpl {
public void doSomeFooStuff() {
System.getenv("FOO_VAR_1");
System.getenv("FOO_VAR_2");
System.getenv("FOO_VAR_3");
// Do the other Foo stuff
}
}
You could do the following:
package com.foo.service.impl;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
import org.junit.Beforea;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(FooServiceImpl.class)
public class FooServiceImpTest {
#InjectMocks
private FooServiceImpl service;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockStatic(System.class); // Powermock can mock static and private methods
when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1");
when(System.getenv("FOO_VAR_2")).thenReturn("test-foo-var-2");
when(System.getenv("FOO_VAR_3")).thenReturn("test-foo-var-3");
}
#Test
public void testSomeFooStuff() {
// Test
service.doSomeFooStuff();
verifyStatic();
System.getenv("FOO_VAR_1");
verifyStatic();
System.getenv("FOO_VAR_2");
verifyStatic();
System.getenv("FOO_VAR_3");
}
}
Decouple the Java code from the Environment variable providing a more abstract variable reader that you realize with an EnvironmentVariableReader your code to test reads from.
Then in your test you can give an different implementation of the variable reader that provides your test values.
Dependency injection can help in this.
This answer to the question How do I set environment variables from Java? provides a way to alter the (unmodifiable) Map in System.getenv(). So while it doesn't REALLY change the value of the OS environment variable, it can be used for unit testing as it does change what System.getenv will return.
Even though I think this answer is the best for Maven projects, It can be achieved via reflect as well (tested in Java 8):
public class TestClass {
private static final Map<String, String> DEFAULTS = new HashMap<>(System.getenv());
private static Map<String, String> envMap;
#Test
public void aTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "155");
assertEquals("155", System.getenv("NUMBER_OF_PROCESSORS"));
}
#Test
public void anotherTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "77");
assertEquals("77", System.getenv("NUMBER_OF_PROCESSORS"));
}
/*
* Restore default variables for each test
*/
#BeforeEach
public void initEnvMap() {
envMap.clear();
envMap.putAll(DEFAULTS);
}
#BeforeAll
public static void accessFields() throws Exception {
envMap = new HashMap<>();
Class<?> clazz = Class.forName("java.lang.ProcessEnvironment");
Field theCaseInsensitiveEnvironmentField = clazz.getDeclaredField("theCaseInsensitiveEnvironment");
Field theUnmodifiableEnvironmentField = clazz.getDeclaredField("theUnmodifiableEnvironment");
removeStaticFinalAndSetValue(theCaseInsensitiveEnvironmentField, envMap);
removeStaticFinalAndSetValue(theUnmodifiableEnvironmentField, envMap);
}
private static void removeStaticFinalAndSetValue(Field field, Object value) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
}
}
Hope the issue is resolved. I just thought to tell my solution.
Map<String, String> env = System.getenv();
new MockUp<System>() {
#Mock
public String getenv(String name)
{
if (name.equalsIgnoreCase( "OUR_OWN_VARIABLE" )) {
return "true";
}
return env.get(name);
}
};
You can use Powermock for mocking the call. Like:
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("MyEnvVariable")).thenReturn("DesiredValue");
You can also mock all the calls with:
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv(Mockito.anyString())).thenReturn(envVariable);
The library https://github.com/webcompere/system-stubs/tree/master/system-stubs-jupiter - a fork of system-lambda - provides a JUnit 5 plug-in:
#ExtendWith(SystemStubsExtension.class)
class SomeTest {
#SystemStub
private EnvironmentVariables environmentVariables =
new EnvironmentVariables("name", "value");
#Test
void someTest() {
// environment is set here
// can set a new value into the environment too
environmentVariables.set("other", "value");
// tidy up happens at end of this test
}
}
The https://junit-pioneer.org/ alternative requires environment variable values to be known at compile time. The above also supports the setting
of environment variables in the #BeforeAll, which means it interoperates well with things like Testcontainers that might set up some resources needed by child tests.
A lot of focus in the suggestions above on inventing ways in runtime to pass in variables, set them and clear them and so on..? But to test things 'structurally', I guess you want to have different test suites for different scenarios? Pretty much like when you want to run your 'heavier' integration test builds, whereas in most cases you just want to skip them. But then you don't try and 'invent ways to set stuff in runtime', rather you just tell maven what you want? It used to be a lot of work telling maven to run specific tests via profiles and such, if you google around people would suggest doing it via springboot (but if you haven't dragged in the springboot monstrum into your project, it seems a horrendous footprint for 'just running JUnits', right?). Or else it would imply loads of more or less inconvenient POM XML juggling which is also tiresome and, let's just say it, 'a nineties move', as inconvenient as still insisting on making 'spring beans out of XML', showing off your ultimate 600 line logback.xml or whatnot...?
Nowadays, you can just use Junit 5 (this example is for maven, more details can be found here JUnit 5 User Guide 5)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
and then
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
and then in your favourite utility lib create a simple nifty annotation class such as
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
#EnabledIfEnvironmentVariable(named = "MAVEN_CMD_LINE_ARGS", matches = "(.*)integration-testing(.*)")
public #interface IntegrationTest {}
so then whenever your cmdline options contain -Pintegration-testing for instance, then and only then will your #IntegrationTest annotated test-class/method fire. Or, if you don't want to use (and setup) a specific maven profile but rather just pass in 'trigger' system properties by means of
mvn <cmds> -DmySystemPop=mySystemPropValue
and adjust your annotation interface to trigger on that (yes, there is also a #EnabledIfSystemProperty). Or making sure your shell is set up to contain 'whatever you need' or, as is suggested above, actually going through 'the pain' adding system env via your POM XML.
Having your code internally in runtime fiddle with env or mocking env, setting it up and then possibly 'clearing' runtime env to change itself during execution just seems like a bad, perhaps even dangerous, approach - it's easy to imagine someone will always sooner or later make a 'hidden' internal mistake that will go unnoticed for a while, just to arise suddenly and bite you hard in production later..? You usually prefer an approach entailing that 'given input' gives 'expected output', something that is easy to grasp and maintain over time, your fellow coders will just see it 'immediately'.
Well long 'answer' or maybe rather just an opinion on why you'd prefer this approach (yes, at first I just read the heading for this question and went ahead to answer that, ie 'How to test code dependent on environment variables using JUnit').
One slow, dependable, old-school method that always works in every operating system with every language (and even between languages) is to write the "system/environment" data you need to a temporary text file, read it when you need it, and then erase it. Of course, if you're running in parallel, then you need unique names for the file, and if you're putting sensitive information in it, then you need to encrypt it.
Simply
Add below maven dependency
<!-- for JUnit 4 -->
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-junit4</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
<!-- for JUnit 5 -->
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-jupiter</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
Inside your test, you can use something similar:
#Rule
public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule();
#Test
public void givenEnvironmentCanBeModified_whenSetEnvironment_thenItIsSet() {
// mock that the system contains an environment variable "ENV_VAR" having value "value1"
environmentVariablesRule.set("ENV_VAR", "value1");
assertThat(System.getenv("ENV_VAR")).isEqualTo("value1");
}
Reference for more details
https://www.baeldung.com/java-system-stubs
You can try to dependent your code also from properties:
public static String host() {
return firstNonBlank(getenv("HOST"), getProperty("host"), "localhost");
}
So, in tests you can easily just add system property And your production code will precede using environment variables:
System.setProperty("HOST", "127.0.0.0");
Neat and clean approach to use mocking of Environment variables in Unit Testing is with the help of #SystemStub which comes as part of below dependency
testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.0.1'
Below changes are on Junit 5 setup
Add below on your class
#ExtendWith(SystemStubsExtension.class)
and now use
#SystemStub
private EnvironmentVariables environmentVariables;
now you can mock the behavior of the environment variables by setting up the required key/value in your test.
For e.g. environmentVariables.set("MY_ENV_VARIABLE", "MY_REQUIRED_VALUE");
and this works perfectly fine, if your code is using environment variables
System.getenv().getOrDefault("MY_ENV_VARIABLE", "false");
Please note, it won't mock System.getProperties() it works only for System.getenv()
Well you can use the setup() method to declare the different values of your env. variables in constants. Then use these constants in the tests methods used to test the different scenario.
I use System.getEnv() to get the map and I keep as a field, so I can mock it:
public class AAA {
Map<String, String> environmentVars;
public String readEnvironmentVar(String varName) {
if (environmentVars==null) environmentVars = System.getenv();
return environmentVars.get(varName);
}
}
public class AAATest {
#Test
public void test() {
aaa.environmentVars = new HashMap<String,String>();
aaa.environmentVars.put("NAME", "value");
assertEquals("value",aaa.readEnvironmentVar("NAME"));
}
}
If you want to retrieve informations about the environment variable in Java, you can call the method : System.getenv();. As the properties, this method returns a Map containing the variable names as keys and the variable values as the map values. Here is an example :
import java.util.Map;
public class EnvMap {
public static void main (String[] args) {
Map<String, String> env = System.getenv();
for (String envName : env.keySet()) {
System.out.format("%s=%s%n", envName, env.get(envName));
}
}
}
The method getEnv() can also takes an argument. For instance :
String myvalue = System.getEnv("MY_VARIABLE");
For testing, I would do something like this :
public class Environment {
public static String getVariable(String variable) {
return System.getenv(variable);
}
#Test
public class EnvVariableTest {
#Test testVariable1(){
String value = Environment.getVariable("MY_VARIABLE1");
doSometest(value);
}
#Test testVariable2(){
String value2 = Environment.getVariable("MY_VARIABLE2");
doSometest(value);
}
}
I have a BaseTest class which consists of several tests. Each test shall be executed for EVERY profile I list.
I thought about using Parameterized values such as:
#RunWith(Parameterized.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
// #ActiveProfiles("h2-test") // <-- how to iterate over this?
public abstract class BaseTest {
#Autowired
private TestRepository test;
// to be used with Parameterized/Spring
private TestContextManager testContextManager;
public BaseTest(String profile) {
System.setProperty("spring.profiles.active", profile);
// TODO what now?
}
#Parameterized.Parameters
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList<>();
params.add(new Object[] {"h2-test" });
params.add(new Object[] {"mysql-test" });
return params;
}
#Before
public void setUp() throws Exception {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
// maybe I can spinup Spring here with my profile?
}
#Test
public void testRepository() {
Assert.assertTrue(test.exists("foo"))
}
How would I tell Spring to run each test with these different profiles? In fact, each profile will talk to different datasources (in-memory h2, external mysql, external oracle, ..) so my repository/datasource has to be reinitialized.
I know that I can specify #ActiveProfiles(...) and I can even extend from BaseTest and override the ActiveProfile annotation. Although this will work, I only show a portion of my test-suite. Lots of my test-classes extend from BaseTest and I don't want to create several different profile-stubs for each class. Currently working, but ugly solution:
BaseTest (#ActiveProfiles("mysql"))
FooClassMySQL(annotation from BaseTest)
FooClassH2(#ActiveProfiles("h2"))
BarClassMySQL(annotation from BaseTest)
BarClassH2(#ActiveProfiles("h2"))
Thanks
For what it's worth:
My use case was to run a specific test class for multiple spring profiles, this is how I achieved it:
#SpringBootTest
abstract class BaseTest {
#Test void doSomeTest() {... ARRANGE-ACT-ASSERT ...}
}
#ActiveProfiles("NextGen")
class NextGenTest extends BaseTest {}
#ActiveProfiles("Legacy")
class LegacyTest extends BaseTest {}
If you use Maven you can actually specify active profile from command line (or env variable if needed):
mvn clean test -Dspring.profiles.active=h2-test
The approach with parameterized test may not work in this case, because profile has to be specified before Spring boots up its context. In this case when you run parameterized integration test the context will be already booted up before test runner starts running your test. Also JUnit's parameterized tests were invented for other reasons (running unit tests with different data series).
EDIT: Also one more thing - when you decide to use #RunWith(Parameterized.class) you wont be able to use different runner. In many cases (if not all if it comes to integration testing) you want to specify different runner, like SpringRunner.class - with parameterized test you wont be able to do it.
Spring profiles are not designed to work in this way.
In your case, each profile uses a specific datasource.
So each one requires a Spring Boot load to run tests with the expected datasource.
In fact, what you want to do is like making as many Maven build as Spring profiles that you want to test.
Besides, builds in local env should be as fast as possible.
Multiplying automated tests execution by DBMS implementation that requires a Spring Boot reload for each one will not help.
You should not need to specify #ActiveProfiles .
It looks rather like a task for a Continuous Integration tool where you could define a job that executes (sequentially or parallely) each Maven build by specifying a specific Spring Boot profile :
mvn clean test -Dspring.profiles.active=h2
mvn clean test -Dspring.profiles.active=mysql
etc...
You can also try to perform it in local by writing a script that performs the execution of the maven builds.
But as said, it will slowdown your local build and also complex it.
I'm trying to have both classes and methods running in parallel.
For example:
Method Tests
public class MethodTests(){
#Test(groups = "testMe")
public void methodTestOne(){
...
}
#Test(groups = "testMe")
public void methodTestTwo(){
...
}
}
Class Tests
-> Hoping the Test annotation on the class level would do it
#Test
public class ClassTests(){
#Test(groups = "testMe")
public void classTestOne(){
...
}
#Test(groups = "testMe")
public void classTestTwo(){
...
}
}
I've included the surefire-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<parallel>all</parallel>
<threadCount>${threads}</threadCount>
...
</plugin>
Note: I've also tried classesAndMethods
I'm running from the command line like this:
mvn clean verify -Dgroups=testMe -Dthreads=3
I'm trying to accomplish the classTests run on one thread, and the method tests use a different thread after being complete.
Purpose:
In the beforeClass, I'm setting up the test, and then quickly asserting multiple things on a page, If one fails, I want it to still test the other things on the page.
Where as, if the method tests fail, I need it to completely stop.
I need both scenarios, and I do not want to use any XML.
I am not sure I quite understand the use case. But the only combinations of parallelism supported by TestNG are as below
tests - causes #Test methods inside tags to run in parallel.
instances - Causes #Test methods inside test class instances to run in parallel.
classes - causes test classes to run in parallel
methods - causes multiple #Test methods to run in parallel
I dont remember seeing something called all. I think that's applicable only to the JUnit provider for Maven surefire plugin. Please see here.
For your scenario as long as you have the #BeforeClass(alwaysRun=true) it would be executed for all groups and it would prevent the test methods that are dependent on the before class to be skipped.
The value that you should be using is classes, like this : <parallel>classes</parallel>
When running all my tests in Eclipse (Eclipse 3.4 'Ganymede'), one test is listed under "Unrooted Tests". I'm using Junit 3.8 and this particular test extends TestCase. I do not see any difference between this test and the other tests. I don't remember seeing this occur in Eclipse 3.3 (Europa).
Clarification:
We haven't moved to JUnit 4.0 yet, so we are not using annotations. I also googled and it seemed like most people were having issues with JUnit 4, but I did not see any solutions. At this point the test passes both locally and in CruiseControl so I'm not overly concerned, but curious.
When I first saw this, though, it was on a failing test that only failed when run with other tests. This led me down the rabbit hole looking for a solution to the "Unrooted" issue that I never found. Eventually I found the culprit in another test that was not properly tearing down.
I agree, it does seem like an Eclipse issue.
Finally I found the solution. The problem is that you are not defining your test cases using annotations but are still doing it the "old way". As soon as you convert over to using annotations you will be able to run one test at a time again.
Here is an example of what a basic test should now look like using annotations:
import static org.junit.Assert.*; // Notice the use of "static" here
import org.junit.Before;
import org.junit.Test;
public class MyTests { // Notice we don't extent TestCases anymore
#Before
public void setUp() { // Note: It is not required to call this setUp()
// ...
}
#Test
public void doSomeTest() { // Note: method need not be called "testXXX"
// ...
assertTrue(1 == 1);
}
}
I was getting the "unrooted tests" error message as well and it went away magically. I believe it was due to the fact that I was using Eclipse with a Maven project. When I added a new method to my Test class and gave it the #Test annotation, it began getting the error message when I tried to run that one method using the "Run as Junit test" menu option; however, once I ran a maven build the unrooted tests message disappeared and I believe that is the solution to the problem in the future.
Run a maven build because it will refresh the class that JUnit is using.
If your class extends TestCase somewhere in its hierarchy, you have to use the JUnit 3 test runner listed in the drop down under run configurations. Using the JUnit 4 runner (the default I believe) causes that unrooted test phenomenon to occur.
I got this error because I renamed my test method and then tried to run the test in Eclipse by clicking on the same run configuration - referring to the old method which now didn't exist.
We solved the problem by making sure our test project was built. We had an issue in the build path which would not allow our test class to be compiled. Once we resolved the build path issue, the test compiled and the "new" method was able to be run. So we can assume that "Unrooted" tests also mean that they don't exist in the compiled binary.
I've never seen this -- but as far as I can tell from skimming Google for a few minutes, this appears as though it could be a bug in Eclipse rather than a problem with your test. You don't have the #Test annotation on the test, I assume? Can you blow the test away and recreate it, and if so do you get the same error?
Another scenario that causes this problem was me blindly copy/pasting a method that requires a parameter. i.e.
import org.junit.Test;
public class MyTest {
#Test
public void someMethod(String param) {
// stuff
}
}
You have a few simple solutions:
define the variable in the specific test method
add it as an instance variable to the test class
create a setup method and annotate it with #Before
For me, it was due to the project got build path issues. My maven dependencies configuration needs to be updated.
I had that problem and putting one "#Test" before the test method solved it!
like this:
#Test
public void testOne() { // ...
assertTrue(1 == 1);
}
These are the two scenarios that the Unrooted errors show up.
If you have missed the annotation #Test before the test.
#Test
public void foo(){
}
If it is a Gwt project and when two mock of the same object are defined. Lets say there is one class Class A and
#GwtMock
private A atest;
#GwtMock
private A a;
Then this will also show a Unrooted test error.
One other thing you can try is to upgrade your version of JUnit to at least 4.12.
I was experiencing this problem for a while with a class that extended one that used #RunWith(Parameterized.class).
After a while, and I'm sorry that I don't know precisely what I did to cause this, the 'Unrooted Tests' message went away, but the test still didn't run correctly. The constructor that should have accepted arguments from the #Parameters method was never getting called; execution jumped straight from #BeforeClass to #AfterClass.
The fix for that problem was to upgrade JUnit from the 4.8.1 it was using, to the latest (4.12). So maybe that could help someone else in the future.
I had the same problem with
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
you need the jar hamcrest.
same question 14539072: java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
I could the fix the issue by shifting from TestRunner ver 4.0 to 3 in run configurations for the individual test method.
Do not extend junit.framework.TestCase in your test class with junit1.4 and this should solve the problem
You are using Hamcrest? or another library to help in your test?. You are not using
import static org.junit.Assert.*;
Check if in your test you use:
import static org.hamcrest.MatcherAssert.assertThat;
or other assert isnĀ“t JUnit assert.
It turned out to be that my build path had some error...some jars were missing.
I reconfigured build path and it worked!
For me the problem was, that an exception was thrown in the #BeforeClass or #AfterClass methods. This will also cause tests to be categorized as unrooted.
I got this error with the test method name as "test"
#Test
public void test() {
// ... assertTrue(1 == 1);
}
I renamed the method and it worked
I ran into this problem by not also declaring the test to be static.
Maybe it's just a logical confusion about the goal of the method. Let's remember:
E.g. correct tagged test method:
#Test
#Transactional
#Rollback(true)
public void testInsertCustomer() {
(...)
}
-With Eclipse Junit plugin, You can run that test method using context menu over the method (E.g. at package explorer expanding the class and methods and selecting "testInsertCustomer()" method and from that item selecting "Run as >> JUnit test").
If you forgot "#Test" tag, or simply the method is not a test, but a (private or not) common method for using as utility for the other tests (e.g. "private fillCustomerObject()"), then the method does not require "#Test" tag, and simply you can not run it as a JUnit test!
It's easy that you could create a utility method and later you forgot the real goal of that method, so if you try to run it as a test, JUnit will shout "Unrooted Tests".
For me this problem was created by a real-time exception thrown in the #AfterClass method (take a look here for documentation):
Basically all the test methods succeeded but at the end of the class this method was failing. Therefore all the tests seems fine but there was on my Eclipse an additional "unrooted test" failed.
I got these errors for a maven project. I rebuild the project with mvn clean install.And the issue was solved
It actually told me there is a test with annotation: #RunWith(MockitoJUnitRunner.class)