105

In my code I need to do certain fixes only when it is run inside a JUnit test. How can I find out if code is running inside a JUnit test or not? Is there something like JUnit.isRunning() == true ?

Dr. Max Völkel
  • 1,780
  • 2
  • 17
  • 24
  • 19
    This is a terrible idea – KitsuneYMG Feb 26 '10 at 13:49
  • of course, still better than not testing at all. Maybe... – Thilo Feb 26 '10 at 16:11
  • 2
    FWIW, I often find it's useful to do *while developing*. Put a check for jUnit in the outer-most method of an API, that throws a run-time exception at the end when being run in-container. This way you can run unit tests and get a valid result, and also test the full stack easily from the UI, but your transaction gets thrown out due to the RTE. – Sophistifunk Feb 25 '13 at 23:28
  • 18
    I think I have a pretty valid use case for this: I want to send an email in production if something goes seriously wrong, and I don't want that email if it's inside of a test case (the developer, as opposed to the production support staff, will see the failed results on his own). We have over a hundred JUnit tests and I don't want to go modify each one to call something like EmailService.dontSendEmailsToProductionTeam() – Ryan Shillington Oct 08 '13 at 19:19
  • 3
    I like to know if code is running within a unit test so I can do things like tell it to use a different S3 bucket. That way I can still test everything is wired up without having to mock out S3 entirely. – Aaron Silverman Jul 08 '14 at 22:34
  • I think it is useful as a safety constraint. Safety constraints seldom do any harm even if "should never happen". – Audrius Meškauskas Sep 03 '14 at 08:58
  • 1
    Your are really violating the idea of TDD if your code if doing something different for the Test. Why do you only need to change it inside the test? – ctrlShiftBryan Feb 26 '10 at 13:43
  • 1
    Another use case: Loading a Mocked instance for a singleton. I'd never want the singleton replaced when running in Production or even in most Development situations, but for some unit tests where the singleton is out of the test's scope, then I do want to replace it! – Stephen M -on strike- Jun 13 '19 at 19:54

10 Answers10

99

It might be a good idea if you want to programmatically decide which "profile" to run. Think of Spring Profiles for configuration. Inside an integration tests you might want to test against a different database.

Here is the tested code that works

public static boolean isJUnitTest() {  
  for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
    if (element.getClassName().startsWith("org.junit.")) {
      return true;
    }           
  }
  return false;
}
zb226
  • 9,586
  • 6
  • 49
  • 79
Janning Vygen
  • 8,877
  • 9
  • 71
  • 102
32

First of all, this a probably not a good idea. You should be unit testing the actual production code, not slightly different code.

If you really want to do this, you could look at the stacktrace, but since you are changing your program for this anyway, you might just as well introduce a new static boolean field isUnitTesting in your code, and have JUnit set this to true. Keep it simple.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Yes, you might for instance have a singleton object in your class containing the isUnitTesting field, and set it to true in a JUnit @Before method. – Jim Ferrans Feb 26 '10 at 13:59
  • 5
    come to think of it, this is a little like dependency injection. He should be injecting mock objects for the dependencies that are too difficult to test, but I suppose that setting a boolean to true explicitly is still better then trying to have the class figure it out by itself. – Thilo Feb 26 '10 at 14:05
  • 1
    Guys, you convinced and encouraged me to rephrase this question. http://stackoverflow.com/questions/2351293/google-appengine-local-junit-tests-jersey-framework-embedded-jetty – Dr. Max Völkel Feb 28 '10 at 14:19
  • 2
    "You should be unit testing the actual production code". No one does this. Unit tests almost always use some form of mocking, which typically implemented by polymorphism (i.e. interfaces). Using a flag is just another way of doing the same thing. The difference is stylistic and relatively insubstantial. – Elliott Beach Sep 25 '19 at 12:27
20

Lots of people on this thread say that it's a bad idea for code to run slightly differently while under JUnit. I generally agree, but I think there are some exceptions.

For example, I am currently writing INTEGRATION (as opposed to Unit) tests for an app that connects to a DB.

These acceptance tests often need to completely reinitialize the DB with specific test data.

Obviously, I don't want this EVER, EVER to be done on an actual production DB, because that might completely erase valuable production data.

The easiest way to guarantee that this will never happen, is to make it impossible for the code to connect to a production DB when it is running under JUnit. This in turn can be done if, for example, the Factory that generates a connection can tell that it's running under JUnit, and in that case, will return a null connection unless the database we are trying to connect to has a name that is known to be a test database (ex: "testdatabase").

kellyfj
  • 6,586
  • 12
  • 45
  • 66
Alain Désilets
  • 509
  • 5
  • 11
  • 7
    This is solvable by making your code not know about the production database. It'll use whatever config is in environment variables or in a specific location. Production config could be a not well-known config (i.e. only exists on deployments, not in version control). This is not only more secure, but also solves the testing issue, and no need for production code modification. – TWiStErRob Jan 13 '18 at 15:37
10

This has worked for me:

private Boolean isRunningTest = null;

private boolean isRunningTest() {
    if (isRunningTest == null) {
        isRunningTest = true;
        try {
            Class.forName("org.junit.Test");
        } catch (ClassNotFoundException e) {
            isRunningTest = false;
        }
    }
    return isRunningTest;
}

It can be used in Maven tests, as well as inside the Eclipse IDE, as long as junit is included as a dependency with scope "test", eg:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>
Andrea M
  • 101
  • 1
  • 3
6

If you're doing things differently because you're doing a unit test you're defeating the purpose of a unit test. A unit test is supposed to perform exactly like production would (except for the setup and teardown of any necessary data and such you need....but that is included in the JUnit test itself and not your code).

However, if you truly do have a good reason for this I'd look at the stack and see if JUnit is there.

SOA Nerd
  • 943
  • 5
  • 12
  • I know this sounds a bit against TDD, but testing code for GoogleAppengine using Jersey/Jetty introduces more than one thread on my local machine, which in turn causes the new threads not to have the right mock testing environment from Google initialised, so I need to check in many points of my potential second thread if my AppEngine mock up env is properly initialised already, which I do not want to do if I am in a production server. I'ts clearly a bit messy and would be better if I could mimic the AppEngine env more closely on my local machine (i.e. have only one thread). – Dr. Max Völkel Feb 26 '10 at 14:17
  • 1
    I think this should be your actual question. How do I get my unit tests to behave the same as the deployed environment. This might help you actually solve your issues without introducing code to actually check whether or not you are running a unit test. – Robin Feb 26 '10 at 14:35
  • Why not test for GAE using the GAE development server? It is pretty close to the real thing, and I believe they even have JUnit support now. – Thilo Feb 26 '10 at 16:13
  • for GAE: if (SystemProperty.environment.value() == null) { // in unit test } – cputoaster Aug 21 '19 at 09:15
5

When using Spring one can define a bean which holds this value.

In application context:

@Bean
public boolean isRunningTests() {
    return false;
}

In test application context:

@Bean
public boolean isRunningTests() {
    return true;
}

Inject the value to a Spring component:

@Resource
private boolean isRunningTests;

private void someMethod() {
    if (isRunningTests()) {
        ....
Milanka
  • 1,742
  • 19
  • 15
5

How about checking if the junit jar is in the classpath?

Derrops
  • 7,651
  • 5
  • 30
  • 60
2

In order to distinguish between test and no test you can always define special property or value in application-test.properties.

Meir G.
  • 46
  • 3
  • Using the following annotation over your unit tests: @TestPropertySource("classpath:application-test.properties") (You may also need to still autowire your Environment object in your unit test class so it's loaded before being injected later on with the wrong properties file,) – Romano Mar 08 '23 at 16:03
2

The shortest (least code) solution is to have a global flag that is set when tests are not running. You can then set it once in your main() (or similar entry point) instead of setting it repeatedly in setup methods of all test classes. This will work as long as there is no other way to enter the code (no alternate main).

The second shortest solution is to scan the call stack for junit package like in Janning's answer. This will work as far as junit doesn't hide itself behind another library and an executor.

Dependency injection will work too, but in this case it's just a fancy way to set what's essentially a global flag.

Robert Važan
  • 3,399
  • 2
  • 25
  • 31
  • "Dependency injection will work too, but in this case it's just a fancy way to set what's essentially a global flag." Hear hear! "Dependency injection" is obfuscation. – barneypitt Oct 02 '22 at 18:16
-1

this is not strictly related to the user question, but I'm pretty sure that someone that get there may find it useful.

I use the following approach: expose a package-local constructor that will be used from tests.

e.g.

src/main/java/ApplicationService.java

public class ApplicationService {
  private final Integer someInternalObject;

  public ApplicationService(String somePublicArgument) throws NumberFormatException {
    someInternalObject = Integer.valueOf(somePublicArgument, 16);
  }

  ApplicationService(Integer someInternalObject) {
     this.someInternalObject = someInternalObject;
  }
}

src/test/ApplicationServiceTest.Java

public class ApplicationServiceTest {
  @Test
  public void testSomething() throws Exception {
    ApplicationService applicationService = new ApplicationService(0);
  }
}

expose it to all tests

not final classes

Extend it in the tests and provide a public constructor for the package-local or protected one.

final classes

Make a public Factory Method in the same package ( within tests ) that will create it using the package-local constructor.

tux_mind
  • 306
  • 1
  • 5
  • 15