Search code examples
javaunit-testingjunittest-suite

Constructing test suites in Junit 4


Right now, I have this simple test suite:

@RunWith(Suite.class)
@Suite.SuiteClasses({
    CommentingTest.class,
    SubscriptionsTest.class,
    EditingTest.class,
    BasicOperationsTest.class
})
public class WebTestSuite { }

But now I want to pass parameters to these test classes, to tell them whether or not to test with an admin account, whether or not to test in view mode A or B, etc. I was hoping I could do something like this:

@RunWith(Suite.class)
public class WebTestSuite {
    public WebTestSuite() {
        this.addTest(new CommentingTest(Accounts.ADMIN, ViewMode.A));
        this.addTest(new CommentingTest(Accounts.ADMIN, ViewMode.B));
        this.addTest(new CommentingTest(Accounts.GUEST, ViewMode.B));
        this.addTest(new SubscriptionsTest(Accounts.ADMIN, ViewMode.A));
        this.addTest(new SubscriptionsTest(Accounts.ADMIN, ViewMode.B));
        this.addTest(new SubscriptionsTest(Accounts.GUEST, ViewMode.B));
        this.addTest(new EditingTest(Accounts.ADMIN, ViewMode.A));
        this.addTest(new EditingTest(Accounts.ADMIN, ViewMode.B));
        this.addTest(new EditingTest(Accounts.GUEST, ViewMode.B));
        this.addTest(new BasicOperationsTest(Accounts.ADMIN, ViewMode.A));
        this.addTest(new BasicOperationsTest(Accounts.ADMIN, ViewMode.B));
        this.addTest(new BasicOperationsTest(Accounts.GUEST, ViewMode.B));
    }
}

But I can't figure out how to do something like this. Any ideas? Thanks!


Solution

  • You can't do it the way you listed because the test classes need to have a no-arg constructor.

    There are 2 options you can do depending on what the tests are like:

    Option 1. Make abstract test classes with subclasses that have the parameters:

    Make the abstract test classes with all of your tests then have subclasses provide the variable information. The abstract class can take parameters in the constructors, the subclass no-arg constructor calls super(...) with the appropriate parameters.

    public abstract class AbstractCommentingTest{
    
        private Account account;
        private ViewMode mode;
    
        public AbstractCommentingTest(Account a, ViewMode v){
           this.account=a;
           this.viewMode = v;
        }
    
    
        //Put your tests here using the given account and view
        @Test
        public void foo(){
    
        }
    
        @Test
        public void bar(){
    
        }
    
    
    }
    

    Then your concrete classes

    public class AdminViewACommentingTest extends AbstractCommentingTest{
          //no-arg constructor for JUnit
          public AdminViewACommentingTest(){
              super(Accounts.ADMIN, Viewmode.A);
          }
    }
    

    This works but can get out of hand quickly if there are lots of options

    Option 2: Use Junit Parameterized tests to have every option combination:

    I assume Accounts and ViewMode are enums ? If so you can easily use the values() method to create all possible combinations as part of a Parameterized test set.

    @RunWith(Parameterized.class)
    public class CommentingTest{
    
         @Parameters
         public static Collection<Object[]> createData(){
                    List<Object[]> data = new ArrayList<Object[]>();
    
                     for(Accounts account : Accounts.values()){
                        for(ViewMode view : ViewMode.values()){
                             data.put(new Object[]{account, view});
                        }
                      }
                     return data;
        }
    
    
        private Account account;
        private ViewMode mode;
    
        public CommentingTest(Account a, ViewMode v){
           this.account=a;
           this.viewMode = v;
        }
    
        //Put your tests here using the given account and view
        @Test
        public void foo(){
    
        }
    
        @Test
        public void bar(){
    
        }
    

    }