简体   繁体   中英

JUnit Contract Testing with Suites

I have an interface that defines a contract (ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM