1

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.

Community
  • 1
  • 1
MiniW
  • 193
  • 13

1 Answers1

0

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.

Carlos Andrés García
  • 1,483
  • 2
  • 15
  • 30
  • How does `FeatureTestSuite` inject dependencies to all of its suite classes? – MiniW May 26 '16 at 12:36
  • @MiniW Another option is using Junit Rules http://stackoverflow.com/a/13489506/1371064 and JUnit Parameters. Obviosly, This depends of sort of test you want to test. In my Case , I always use Spring and innject dependencies with its context. Here an example how to http://stackoverflow.com/a/14946430/1371064 – Carlos Andrés García May 26 '16 at 14:26