74

I read about Structuring Unit Tests with having a test class per class and an inner class per method. Figured that seemed like a handy way to organize the tests, so I tried it in our Java project. However, the tests in the inner classes doesn't seem to be picked up at all.

I did it roughly like this:

public class DogTests
{
    public class BarkTests
    {
        @Test
        public void quietBark_IsAtLeastAudible() { }

        @Test
        public void loudBark_ScaresAveragePerson() { }
    }

    public class EatTests
    {
        @Test
        public void normalFood_IsEaten() { }

        @Test
        public void badFood_ThrowsFit() { }
    }
}

Does JUnit not support this, or am I just doing it wrong?

Svish
  • 138,188
  • 158
  • 423
  • 589
  • 1
    I think if you declare the inner classes `static`, it should work. – Stephan Jan 06 '12 at 13:16
  • See here: http://stackoverflow.com/questions/4150490/error-when-defining-inner-classes-in-a-test-class-in-junit – cuh Jan 06 '12 at 13:20

5 Answers5

92

You should annontate your class with @RunWith(Enclosed.class), and like others said, declare the inner classes as static:

@RunWith(Enclosed.class)
public class DogTests
  {
  public static class BarkTests
  {
    @Test
    public void quietBark_IsAtLeastAudible() { }

    @Test
    public void loudBark_ScaresAveragePerson() { }
  }

  public static class EatTests
  {
    @Test
    public void normalFood_IsEaten() { }

    @Test
    public void badFood_ThrowsFit() { }
  }
}
Theodor
  • 4,937
  • 12
  • 38
  • 53
  • You can still only run 1 class at a time. – Sridhar Sarnobat Jan 24 '17 at 23:41
  • 3
    Works for me. At least in Intellij I can either run all tests, only tests from one child class, or a single test. With code folding this is really nice! – Willey Feb 03 '17 at 14:06
  • Runs all tests for me using Eclipse Neon and JUnit 4.12. Eclipse also prompts to run the outer fixture or one of the nested fixtures. The only problem I have is, when run from Gradle, tests from the nested fixtures are run twice. [GRADLE-2843](https://issues.gradle.org/browse/GRADLE-2843) was opened for this issue in 2013, but it has since been abandoned. – Rusty Shackleford May 31 '17 at 01:45
  • also note inner class must be public. – tkruse Feb 28 '19 at 08:22
  • This appears to be outdated - see https://stackoverflow.com/a/22546453/5209935 – Matthew Apr 24 '20 at 08:26
31
public class ServicesTest extends TestBase {

   public static class TestLogon{

       @Test
       public void testLogonRequest() throws Exception {
         //My Test Code
       }
   }
}

Making the inner class static works for me.

n3utrino
  • 2,319
  • 2
  • 21
  • 31
18

In JUnit 5, you simply mark non-static inner classes as @Nested:

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

public class DogTests {
    @Nested
    public class BarkTests {
        @Test
        public void quietBark_IsAtLeastAudible() { }

        @Test
        public void loudBark_ScaresAveragePerson() { }
    }

    @Nested
    public class EatTests {
        @Test
        public void normalFood_IsEaten() { }

        @Test
        public void badFood_ThrowsFit() { }
    }
}
heenenee
  • 18,987
  • 1
  • 49
  • 81
14

I think some of the answers might be for older versions of JUnit. In JUnit 4 this worked for me:

    @RunWith(Suite.class)
    @Suite.SuiteClasses({ DogTests.BarkTests.class, DogTests.EatTests.class })
    public class DogTests
    {
        public static class BarkTests
        {
            @Test
            public void quietBark_IsAtLeastAudible() { }

            @Test
            public void loudBark_ScaresAveragePerson() { }
        }

        public static class EatTests
        {
            @Test
            public void normalFood_IsEaten() { }

            @Test
            public void badFood_ThrowsFit() { }
        }
    }
Matthew
  • 7,232
  • 2
  • 30
  • 50
Kai G
  • 3,062
  • 3
  • 22
  • 27
  • 5
    It works for me without `extends Suite` and the associated constructor. – Nicolas Oct 14 '14 at 21:19
  • 2
    Instead of `extends Suite`, you could make it `@RunWith(Suite.class)`. This is how it is used in the documentation: http://junit.sourceforge.net/javadoc/org/junit/runners/Suite.html – mejdev Mar 20 '17 at 15:10
  • I've updated the example with the lated JUnit4 syntax, hope that's ok. – Matthew Apr 24 '20 at 08:25
10

I've had success with Nitor Creation's Nested Runner as well.

How to use Nitor Creation's Nested Runner

There is a post explaining it here:

Add this dependency:

<dependency>
    <groupId>com.nitorcreations</groupId>
    <artifactId>junit-runners</artifactId>
    <version>1.2</version>
    <scope>test</scope>
</dependency>

And a @RunWith to your test:

import com.nitorcreations.junit.runners.NestedRunner
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
  
@RunWith(NestedRunner.class)
public class RepositoryUserServiceTest {
           
    public class RegisterNewUserAccount {
     
        public class WhenUserUsesSocialSignIn {
             
            public class WhenUserAccountIsFoundWithEmailAddress {
                 
                @Test
                public void shouldThrowException() {
                     assertTrue(true);
                }
            }
         
        }
    }
}

PS: The example code has been taken and modified from the above blog post

Community
  • 1
  • 1
alvaro g
  • 503
  • 5
  • 14