Test cases in inner classes with JUnit - java

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?

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() { }
}
}

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.

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() { }
}
}

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() { }
}
}

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

I just ran across this posting (11 years later) regarding the testing of inner classes. An inner class can be trivially converted to equivalent static form only if the class should have been static in the first place. Static inner classes are not really inner classes because there is no enclosing this. They have exactly the same semantics (except for visibility restrictions) as top-level classes.
To test a "true" inner class [one that depends on its enclosing instance] you need to use the interface that the Java language provides for creating inner class instances outside the scope of the enclosing class. That interface includes an extra parameter in each constructor which is the enclosing instance. In this way, the Java compiler converts an inner class to a special top-level class with a mangled name (lots of $ signs) and augmented constructors. The same transformation can be performed at the source level. In principle, these transformed classes can be tested but it is a complex process because the tested program has transformed syntax and the test code must construct a (mock) object that serves as the enclosing instance.
Another way to test true inner classes is to write an executable method contract for each method consisting of an executable logical pre-condition and an executable logical post-condition. Then these executable contracts can be evaluated in the course of running a conventional top-level test that invokes the inner class methods.
In practice, I typically settle for the indirect testing of inner class methods in the course of top-level testing. Writing and testing executable contracts for all methods is a more rigorous, albeit significantly more expensive, alternative.

Related

#DeclareParents fail to introduce new method

everybody, I am a beginner in Spring and I am encountering some problems with #DeclareParents. I follow the instructions in Spring In Action but I fail to realize the introduction.
Here are my codes.
I first define Interface performance
public interface Performance {
void perform();
}
and then implement the interface.
#Component
public class OnePerformance implements Performance {
#Autowired
public OnePerformance(){
}
public void perform() {
System.out.println("The Band is performing....");
}
}
I want to introduce method void performEncore() into Performance.
So I define the Interface,
public interface Encoreable {
void performEncore();
}
implement it,
#Aspect
public class DefaultEncoreable implements Encoreable{
public void performEncore() {
System.out.println("performEncore");
}
}
and introduce it,
#Aspect
#Component
public class EncoreableIntroduction {
#DeclareParents(value="Performance+",
, defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
I use autoconfiguration,
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class ConcertConfig {
}
However, when testing, I fail to introduce method void performEncore().
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
performance.perform();
}}
And I also enabled AspectJ Support Plugins.
I have read the book and several blogs carefully but I still can not find the cause. So what may be the cause of this problem? Thanks in advance.
Thanks for M. Deinum, NewUser and Wim Deblauwe. With their help, I finally figured out the problem. The previous JUnit4 class is not correct.
The proper solution to solve this problem is to cast Performance into Encoreable, and then call the performEncore() method.
The code is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
Encoreable encoreable = (Encoreable)(performance);
encoreable.performEncore();
}
}

JUnit Contract Testing with Suites

I have an interface that defines a contract (i.e. a Repository), with few implementations. Each method in the interface represents a feature, and I would like to test each feature in its suite test class.
Let's assume a UserRepository interface as follows:
public interface UserRepository {
Set<User> search(String query);
Set<User> findBySomethingSpecific(String criteria1, Integer criteria2);
}
At the moment, to ensure I run the same test cases, I create an abstract test class, and each of my implementations have a test class that extends the abstract test class.
public abstract UserRepositoryTest {
private UserRepository userRepository;
#Before
public void setUp() {
userRepository = createUserRepository();
}
#Test public void aTestForSearch() { ... }
#Test public void anotherTestForSearch() { ... }
#Test public void aTestForSomethingSpecific() { ... }
#Test public void anotherTestForSomethingSpecific() { ... }
protected abstract UserRepository createUserRepository();
}
//------------------------
public class UserRepositoryImplementationTest extends UserRepositoryTest {
#Override
protected UserRepository createUserRepository() {
return new UserRepositoryImplementation();
}
}
I would like to find a way to divide this abstract test class into a set of small tests, because the test class becomes rapidly overwhelmed. I've looked at test suites, but I don't understand how can I create a Suite test class by injecting my different implementations.
As a side not, I've found this question, but some of my repositories require some logic at its creation (for instance, ConnectionPool for a SQL implementation). I currently use the anti-pattern ServiceLocator with different Context classes to handle the creation, but this is static. That's why I had an approach of a test class by implementation, so I can create the context and inject it afterward.
Whit Junit 4 you can create a suite like this:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestFeatureLogin.class,
TestFeatureLogout.class,
TestFeatureNavigate.class,
TestFeatureUpdate.class
})
/**
*
* This suite will execute TestFeatureLogin,TestFeatureLogout,TestFeatureNavigate and TestFeatureUpdate one after the over.
*
* #Before, #After and #Test are no possible of executing in this class.
* #BeforeClas and #AfterClass are allowed only.
*
* */
public class FeatureTestSuite {
// the class remains empty of test,although it is possible set up a before class and after class annotations.
// used only as a holder for the above annotations
#BeforeClass
static public void beforeClass(){
System.out.println(FeatureTestSuite.class.toString() + " BeforeClass Method");
}
#AfterClass
static public void AfterClass(){
System.out.println(FeatureTestSuite.class.toString() + " AfterClass Method");
}
}
The complete example could be found here
Another thing you have to have into account is that #Test is no a good practice of unit testing inside Abstract class. If you want to test your implementations create test classes that extend of Abstract class.

How to avoid ignore tests if I use inner classes for unit testing architecting?

I have following architecture of unit test:
#RunWith(Enclosed.class)
public class ProductTest {
#RunWith(MockitoJUnitRunner.class)
public static abstract class Base {...}
public static class Test1 extends Base{
#Test
public void foo(){...}
}
}
public static class Test2 extends Base{
#Test
public void bar(){...}
}
}
}
If I run unit tests I see following error message:
org.mockito.exceptions.base.MockitoException:
No tests found in Base
Haven't you forgot #Test annotation?
Mockito tries to say me that Base is test bit have noone method annoted with #Test
I have found decision - ignore base class.
Bit it looks like hack. Is there more elegant way?
Move Base outside the ProductTest class (can be in same file) and move RunWith to concrete classes.

How to parameterize junit Test Suite

Is it possible to parameterize a TestSuite in junit 4 ?
For declaring a class as a test suite I need the annotation #RunWith(Suite.class), but the same annotation is also needed to declare the test as parameterized: #RunWith(Parameterized.class) so I cannot add both to the same class.
I found a similar question in this site that did not help much. So far, all the examples I have found explain how to parameterize simple unit tests, not a complete test tuite.
I believe the basic answer is No, because as you said, the #RunsWith only take one parameter. I found a blog posting that got a bit creative in how to handle this situation.
We don't use the parameterized tests, but may you could create a separate suite like we do that only lists the test classes and the parameterized test could be part of that. I modified our test suite to include a parameterized test class to part of the suite and it ran fine. We create our suite like below where PrimeNumberCheckerTest was a simple I pulled from the web.
package com.jda.portfolio.api.rest.server;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({ com.mycompany.api.rest.server.resource.TestCartResourceJava.class,
com.mycompany.api.rest.server.resource.TestCustomerResource.class,
com.mycompany.api.rest.server.resource.TestWizardProfileResource.class,
com.mycompany.api.rest.server.interceptor.TestBaseSearchInterceptor.class,
com.mycompany.api.rest.server.resource.TestQueryParameters.class,
com.mycompany.api.rest.server.expression.TestCartExpressionGenerator.class,
com.mycompany.api.rest.server.expression.TestPreferenceExpressionGenerator.class,
com.mycompany.api.rest.server.PrimeNumberCheckerTest.class,
})
public class AllTests {}
Here's the source for the parameterized test case;
package com.jda.portfolio.api.rest.server:
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Parameterized.class)
#SuiteClasses({PrimeNumberCheckerTest.class})
public class PrimeNumberCheckerTest {
private Integer inputNumber;
private Boolean expectedResult;
private PrimeNumberChecker primeNumberChecker;
#Before
public void initialize() {
primeNumberChecker = new PrimeNumberChecker();
}
// Each parameter should be placed as an argument here
// Every time runner triggers, it will pass the arguments
// from parameters we defined in primeNumbers() method
public PrimeNumberCheckerTest(Integer inputNumber,
Boolean expectedResult) {
this.inputNumber = inputNumber;
this.expectedResult = expectedResult;
}
#Parameterized.Parameters
public static Collection primeNumbers() {
return Arrays.asList(new Object[][] {
{ 2, true },
{ 6, false },
{ 19, true },
{ 22, false },
{ 23, true }
});
}
// This test will run five times since we have as many parameters defined
#Test
public void testPrimeNumberChecker() {
System.out.println("Parameterized Number is : " + inputNumber);
assertEquals(expectedResult,
primeNumberChecker.validate(inputNumber));
}
I was able to parameterize a test suite and use its data in a test class member of the suite as follows:
In JUTsuite:
#RunWith(Suite.class)
#Suite.SuiteClasses({
JUT_test1.class,
})
public class JUTSuite{
// Declare all variables/objects you want to share with the test classes, e.g.
protected static List<Fx> globalFxs;
// This is the data list we'll use as parameters
protected static List<Dx> globalDxs;
#Parameters
public static Collection<Object[]> data(){
// Instantiate object list for parameters.
// Note: you must do it here and not in, say, #BeforeClass setup()
// e.g.
globalDxs=new ArrayList<Dx>(serverObj.values());
Collection<Object[]> rows=new ArrayList<Object[]>();
for(Dx d:globalDxs) {
rows.add(new Object[]{d});
}
return rows;
}
#BeforeClass
public static void setUp() throws Exception {
// Instantiate/initialize all suite variables/objects to be shares with test classes
// e.g. globalFxs=new ArrayList<Fx>();
}
#AfterClass
public static void tearDown() throws Exception {
// Clean up....
}
}
Next, in test class:
#RunWith(Parameterized.class)
public class JUT_test1 {
// declare local names (if desired) for suite-wide variable/objects
// e.g.
private static List<Fx> globalFxs;
// This is the test parameter:
private Dx d;
public JUT_test1(Dx d){
this.d=d;
}
#Parameters
public static Collection<Object[]> data(){
// Note: we're calling the suite's data() method which has already executed.
return JUTSuite.data();
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
// (If desired)initialize local variables by referencing suite variables.
// e.g.globalFxs=JUTSuite.globalFxs;
}
}
I agree, it's not possible with the provided classes, but there are workarounds that will get you most of the way there, like #mikemil's.
I've spent some time extending Suite and delegating to Parameterized, with partial success; it is possible to build runner that does what you want, and the code is more-or-less written for you in those two classes. The way those classes interact (in particular, the definition of Parameterized#getChildren()) makes it difficult to extend or delegate to those classes to accomplish what you need, but creating a whole new class than extends ParentRunner and lifts code from the other two would be fairly easy.
I'll try to get more time to come back to this later. If you do build a new runner before I get around to it, please post it as an answer, I'd love to use it myself.
the best solution will be, keep suit classes separately in a blank class.
For example, I am testing logins as Parameterized tests and putting in a suit (for navigation performance measurement)
#RunWith(Suite.class)
#Suite.SuiteClasses({
LoginPageTest.class,
HomePageTests.class})
public class PerformanceTests {
}
and LoginPageTest is actually Parameterizedtests
#RunWith(Parameterized.class)
public class LoginPageTest
{...}
As already stated multiple times, it's not possible to parameterize a test suite with the runners provided by JUnit 4.
Anyway, I wouldn't recommend to make your testclasses dependent from some externally provided state. What if you want to run a single testclass?
I would recommend to make your separate test classes #Parameterized and use a utility class to provide the parameters:
#RunWith(Suite.class)
#SuiteClasses({ Test1.class, Test2.class })
public class TestSuite {
// suite
}
#RunWith(Parameterized.class}
public class Test1 {
public Test1(Object param1) { /* ... */ }
#Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
#Test
public void someTest() { /* ... */ }
}
#RunWith(Parameterized.class}
public class Test2 {
public Test2(Object param1) { /* ... */ }
#Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
#Test
public void someOtherTest() { /* ... */ }
}
class TestParameters {
public static Collection<Object[]> provideTestData() {
Collection<Object[]> data = new ...;
// build testdata
return data;
}
You're right: Both Suite and Parameterized are Runners and only one Runner may be used to run a test at a time. Standard JUnit 4 doesn't provide a combined Runner.
You can either implement your own Runner or have a look at this ready-to-use library which provides a ParameterizedSuite Runner: https://github.com/PeterWippermann/parameterized-suite
A parameterized test suite looks like this:
#RunWith(ParameterizedSuite.class)
#SuiteClasses({OneTest.class, TwoTest.class})
public class MyParameterizedTestSuite {
#Parameters(name = "Parameters are {0} and {1}")
public static Object[] params() {
return new Object[][] {{'A',1}, {'B',2}, {'C',3}};
}
Maybe this answer helps: Parameterized unit test suites
It uses #RunWith(Enclosed.class) and seems to solve the problem.

Do JUnit test suites support custom annotations?

In JUnit, you can create test suites like so:
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest1.class, SecurityTest2.class})
public class SecurityTestSuite {}
But this seems rather cumbersome. It would be so nice to define a simple class-level annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SecurityTest {}
And then define your suite like so:
#SecurityTest
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
#SecurityTest
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest.class})
public class SecurityTestSuite {}
Is this possible? If so how? Note: not interested in switching to TestNG or any other test framework if JUnit does not support this...thanks in advance!
You can do it by implementing your own Test Runner similar to the Suite runner.
This runner should extract the marker annotation class from the value of the #SuiteClasses annotation (you should probably replace #SuiteClasses with your own annotation). Take a look at the getAnnotatedClasses method of the org.junit.runners.Suite class.
After having the marker annotation class, you should scan the classpath for test classes marked with this annotation (use a library such as Reflections) and pass an array of them to the appropriate Runner constructor.
You can find a similar behavior in the Suite constructor:
public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
this(builder, klass, getAnnotatedClasses(klass));
}

Categories