package com.softwaremill.common.test.util.reorder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.testng.IMethodInstance;
import org.testng.ITestNGMethod;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test class for TestNGReorderingListener
*
* @author Tomasz Dziurko
*/
public class TestNGReorderingListenerTest {
private TestNGReorderingListener listener = new TestNGReorderingListener();
@Test
public void shouldFindNoErrorsInValidMethodsList() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(true, false));
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(false, true));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList).isEmpty();
}
@Test
public void shouldFindNoErrorsInNoAnnotatedMethodsList() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(false, false));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList).isEmpty();
}
@Test
public void shouldFindNoErrorsInDependantMethodsListWithoutAnnotations() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodDependantUponOtherMethods());
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList).isEmpty();
}
@Test
public void shouldNotAllowForMultipleFirstTestAnnotations() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(true, false));
methods.add(mockIMethodAnnotatedWith(true, false));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains("more than one method marked with annotation " + FirstTest.class.getSimpleName());
}
@Test
public void shouldNotAllowForMultipleLastTestAnnotations() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, true));
methods.add(mockIMethodAnnotatedWith(false, true));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains("more than one method marked with annotation " + LastTest.class.getSimpleName());
}
@Test
public void shouldNotAllowForMethodAnnotatedWithFirstAndLastAnnotation() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(true, true));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains("single method can not be annotated with both " +
FirstTest.class.getSimpleName() + " and " + LastTest.class.getSimpleName());
}
@Test
public void shouldNotAllowForMethodAnnotatedWithFirstAndTestOrderAnnotation() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(true, false, true));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains("single method can not be annotated with both " +
FirstTest.class.getSimpleName() + " and " + TestOrder.class.getSimpleName());
}
@Test
public void shouldNotAllowForMethodAnnotatedWithLastAndTestOrderAnnotation() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, true, true));
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains("single method can not be annotated with both " +
LastTest.class.getSimpleName() + " and " + TestOrder.class.getSimpleName());
}
@Test
public void shouldNotAllowForDependantMethodAndMethodWithFirstTestInTheSameClass() throws Exception {
// given
List<String> problemsList = Lists.newArrayList();
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(true, false));
methods.add(mockIMethodDependantUponOtherMethods());
// when
problemsList = listener.checkMethodsInClass(this.getClass(), methods, problemsList);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains(": " + FirstTest.class.getSimpleName() +
" annotation can not be used in method with dependsOnMethods from @Test");
}
@Test
public void shouldFindNoProblemsInProperClassesList() throws Exception {
// given
HashSet<Class> classes = Sets.newHashSet();
classes.add(String.class);
classes.add(FirstTestAnnotatedClassNumberOne.class);
classes.add(ClassWithMethodsToTest.class);
// when
List<String> problemsList = listener.checkForInvalidUsagesInClasses(classes);
// then
assertThat(problemsList.isEmpty()).isTrue();
}
@Test
public void shouldFindProblemsWithMultipleClassesAnnotatedWithFirstTest() throws Exception {
// given
HashSet<Class> classes = Sets.newHashSet();
classes.add(String.class);
classes.add(FirstTestAnnotatedClassNumberOne.class);
classes.add(FirstTestAnnotatedClassNumberTwo.class);
classes.add(ClassWithMethodsToTest.class);
// when
List<String> problemsList = listener.checkForInvalidUsagesInClasses(classes);
// then
assertThat(problemsList.size()).isEqualTo(1);
assertThat(problemsList.get(0)).contains(FirstTestAnnotatedClassNumberOne.class.getSimpleName());
assertThat(problemsList.get(0)).contains(FirstTestAnnotatedClassNumberTwo.class.getSimpleName());
assertThat(problemsList.get(0)).contains("Only one class can be annotated this way");
}
@Test
public void shouldNotReorderMethodsWithoutAnnotations() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodDependantUponOtherMethods());
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.methodName").containsExactly(
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.METHOD_DEPENDANT_UPON_OTHER_METHODS);
}
@Test
public void shouldMoveSelectedMethodToTheFirstPlace() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(true, false));
methods.add(mockIMethodAnnotatedWith(false, false));
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.methodName").containsExactly(
ClassWithMethodsToTest.WITH_FIRST_TEST_ANNOTATION,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS);
}
@Test
public void shouldMoveSelectedMethodToTheLastPlace() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(false, true));
methods.add(mockIMethodAnnotatedWith(false, false));
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.methodName").containsExactly(
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITH_LAST_TEST_ANNOTATION);
}
@Test
public void shouldReorderMethods() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodWithTestOrderAnnotationWithParamTen());
methods.add(mockIMethodAnnotatedWith(false, true));
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(true, false));
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodWithTestOrderAnnotationWithParamOne());
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.methodName").containsExactly(
ClassWithMethodsToTest.WITH_FIRST_TEST_ANNOTATION,
ClassWithMethodsToTest.WITH_TEST_ORDER_ONE,
ClassWithMethodsToTest.WITH_TEST_ORDER_TEN,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITHOUT_ANNOTATIONS,
ClassWithMethodsToTest.WITH_LAST_TEST_ANNOTATION);
}
@Test
public void shouldOrderMethodsUsingTestOrderAnnotation() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodWithTestOrderAnnotationWithParamTen());
methods.add(mockIMethodWithTestOrderAnnotationWithParamOne());
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.methodName").containsExactly(
ClassWithMethodsToTest.WITH_TEST_ORDER_ONE,
ClassWithMethodsToTest.WITH_TEST_ORDER_TEN);
}
@Test
public void shouldPlaceFirstTestAnnotatedClassInFirstPlace() throws Exception {
// given
List<IMethodInstance> methods = Lists.newArrayList();
methods.add(mockIMethodAnnotatedWith(false, false));
methods.add(mockIMethodAnnotatedWith(FirstTestAnnotatedClassNumberOne.class, false, true));
methods.add(mockIMethodAnnotatedWith(false, false));
// when
List<IMethodInstance> reorderedMethods = listener.reorder(listener.distributeMethodsByClass(methods));
// then
assertThat(reorderedMethods).extracting("method.realClass.simpleName").containsExactly(
FirstTestAnnotatedClassNumberOne.class.getSimpleName(),
ClassWithMethodsToTest.class.getSimpleName(),
ClassWithMethodsToTest.class.getSimpleName());
}
private IMethodInstance mockIMethodAnnotatedWith(boolean firstTestAnnotation, boolean lastTestAnnotation,
boolean orderAnnotation) throws Exception {
return mockIMethodAnnotatedWith(ClassWithMethodsToTest.class, firstTestAnnotation,
lastTestAnnotation, orderAnnotation);
}
private IMethodInstance mockIMethodAnnotatedWith(boolean firstTestAnnotation, boolean lastTestAnnotation) throws Exception {
return mockIMethodAnnotatedWith(ClassWithMethodsToTest.class, firstTestAnnotation, lastTestAnnotation);
}
private IMethodInstance mockIMethodAnnotatedWith(Class methodClass, boolean firstTestAnnotation,
boolean lastTestAnnotation) throws Exception {
return mockIMethodAnnotatedWith(methodClass, firstTestAnnotation, lastTestAnnotation, false);
}
private IMethodInstance mockIMethodAnnotatedWith(Class methodClass, boolean firstTestAnnotation,
boolean lastTestAnnotation, boolean orderAnnotation) throws Exception {
IMethodInstance methodInstance = mock(IMethodInstance.class);
ITestNGMethod testNgMethod = mock(ITestNGMethod.class);
when(methodInstance.getMethod()).thenReturn(testNgMethod);
when(testNgMethod.getRealClass()).thenReturn(methodClass);
String methodName;
if (firstTestAnnotation && lastTestAnnotation && orderAnnotation == true) {
methodName = ClassWithMethodsToTest.WITH_TEST_ORDER_ONE_AND_FIRST_AND_LAST_ANNOTATION;
} else if (firstTestAnnotation && lastTestAnnotation && orderAnnotation == false) {
methodName = ClassWithMethodsToTest.WITH_FIRST_AND_LAST_ANNOTATION;
} else if (firstTestAnnotation && orderAnnotation == true) {
methodName = ClassWithMethodsToTest.WITH_TEST_ORDER_ONE_AND_FIRST_TEST;
}
else if (firstTestAnnotation && orderAnnotation == false) {
methodName = ClassWithMethodsToTest.WITH_FIRST_TEST_ANNOTATION;
}
else if (lastTestAnnotation && orderAnnotation == true) {
methodName = ClassWithMethodsToTest.WITH_TEST_ORDER_ONE_AND_LAST_TEST;
}
else if (lastTestAnnotation && orderAnnotation == false) {
methodName = ClassWithMethodsToTest.WITH_LAST_TEST_ANNOTATION;
}
else if(orderAnnotation == true) {
methodName = ClassWithMethodsToTest.WITH_TEST_ORDER_ONE;
}
else {
methodName = ClassWithMethodsToTest.WITHOUT_ANNOTATIONS;
}
mockWithMethod(testNgMethod, methodName);
when(testNgMethod.getMethodsDependedUpon()).thenReturn(new String[]{});
return methodInstance;
}
private void mockWithMethod(ITestNGMethod testNgMethod, String methodName) throws NoSuchMethodException {
Method method = ClassWithMethodsToTest.class.getMethod(methodName);
when(testNgMethod.getMethod()).thenReturn(method);
when(testNgMethod.getMethodName()).thenReturn(methodName);
}
private IMethodInstance mockIMethodDependantUponOtherMethods() throws Exception {
return mockIMethodDependantUponOtherMethods(ClassWithMethodsToTest.class);
}
private IMethodInstance mockIMethodDependantUponOtherMethods(Class methodClass) throws Exception {
IMethodInstance methodInstance = mock(IMethodInstance.class);
ITestNGMethod testNgMethod = mock(ITestNGMethod.class);
when(methodInstance.getMethod()).thenReturn(testNgMethod);
when(testNgMethod.getRealClass()).thenReturn(methodClass);
when(testNgMethod.getMethodsDependedUpon()).thenReturn(new String[]{"method1, method2"});
Method methodWithoutAnnotations = ClassWithMethodsToTest.class.getMethod(ClassWithMethodsToTest.WITHOUT_ANNOTATIONS);
when(testNgMethod.getMethod()).thenReturn(methodWithoutAnnotations);
when(testNgMethod.getMethodName()).thenReturn(ClassWithMethodsToTest.METHOD_DEPENDANT_UPON_OTHER_METHODS);
return methodInstance;
}
private IMethodInstance mockIMethodWithTestOrderAnnotationWithParamOne() throws Exception {
IMethodInstance methodInstance = mock(IMethodInstance.class);
ITestNGMethod testNgMethod = mock(ITestNGMethod.class);
when(methodInstance.getMethod()).thenReturn(testNgMethod);
when(testNgMethod.getRealClass()).thenReturn(ClassWithMethodsToTest.class);
mockWithMethod(testNgMethod, ClassWithMethodsToTest.WITH_TEST_ORDER_ONE);
when(testNgMethod.getMethodsDependedUpon()).thenReturn(new String[]{});
return methodInstance;
}
private IMethodInstance mockIMethodWithTestOrderAnnotationWithParamTen() throws Exception {
IMethodInstance methodInstance = mock(IMethodInstance.class);
ITestNGMethod testNgMethod = mock(ITestNGMethod.class);
when(methodInstance.getMethod()).thenReturn(testNgMethod);
when(testNgMethod.getRealClass()).thenReturn(ClassWithMethodsToTest.class);
mockWithMethod(testNgMethod, ClassWithMethodsToTest.WITH_TEST_ORDER_TEN);
when(testNgMethod.getMethodsDependedUpon()).thenReturn(new String[]{});
return methodInstance;
}
/**
* Hack classes as a workaround to problem with prohibited mocking final classes with Mockito.
* We use some real Method and Class objects annotated with our tested annotations
*/
private class ClassWithMethodsToTest {
public static final String WITH_FIRST_AND_LAST_ANNOTATION = "withFirstAndLastAnnotation";
public static final String WITH_FIRST_TEST_ANNOTATION = "withFirstTestAnnotation";
public static final String WITH_LAST_TEST_ANNOTATION = "withLastTestAnnotation";
public static final String WITHOUT_ANNOTATIONS = "withoutAnnotations";
public static final String METHOD_DEPENDANT_UPON_OTHER_METHODS = "methodDependantUponOtherMethods";
public static final String WITH_TEST_ORDER_ONE = "withTestOrderOne";
public static final String WITH_TEST_ORDER_TEN = "withTestOrderTen";
public static final String WITH_TEST_ORDER_ONE_AND_FIRST_TEST = "withTestOrderOneAndFirstTest";
public static final String WITH_TEST_ORDER_ONE_AND_LAST_TEST = "withTestOrderOneAndLastTest";
public static final String WITH_TEST_ORDER_ONE_AND_FIRST_AND_LAST_ANNOTATION = "withTestOrderOneAndFirstAndLastAnnotation";
@FirstTest
public void withFirstTestAnnotation() {
}
@LastTest
public void withLastTestAnnotation() {
}
public void withoutAnnotations() {
}
@FirstTest
@LastTest
public void withFirstAndLastAnnotation() {
}
@TestOrder(order = 1)
public void withTestOrderOne() {
}
@TestOrder(order = 10)
public void withTestOrderTen() {
}
@FirstTest
@TestOrder(order = 1)
public void withTestOrderOneAndFirstTest() {
}
@LastTest
@TestOrder(order = 1)
public void withTestOrderOneAndLastTest() {
}
@FirstTest
@LastTest
@TestOrder(order = 1)
public void withTestOrderOneAndFirstAndLastAnnotation() {
}
}
@FirstTest
private class FirstTestAnnotatedClassNumberOne {
}
@FirstTest
private class FirstTestAnnotatedClassNumberTwo {
}
}