wrong junit test names - java

I try to write own junit runner and currently I am stuck at returning proper test description.
public class ParameterizedWrapper extends Suite {
private List<Runner> fRunners;
/**
* #throws Throwable
*
*/
public ParameterizedWrapper(final Class<?> clazz) throws Throwable {
super(clazz, Collections.<Runner>emptyList());
fRunners = constructRunners(getParametersMethod());
}
protected List<Runner> constructRunners(final FrameworkMethod method) throws Exception, Throwable {
#SuppressWarnings("unchecked")
Iterable<Object[]> parameters = (Iterable<Object[]>) getParametersMethod().invokeExplosively(null);
ArrayList<Runner> runners = new ArrayList<Runner>();
int index = 0;
for (Object[] parameter : parameters) {
Class<?> testClass = getTestClass().getJavaClass();
WrappedRunner wrappedRunner = testClass.getAnnotation(WrappedRunner.class);
Runner runner = wrappedRunner.value().getConstructor(Class.class).newInstance(getTestClass().getJavaClass());
runners.add(new WrappingRunner(runner, parameter, testClass, index++));
}
return runners;
}
private FrameworkMethod getParametersMethod() throws Exception {
List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(Parameters.class);
for (FrameworkMethod each : methods) {
if (each.isStatic() && each.isPublic()) {
return each;
}
}
throw new Exception("No public static parameters method on class " + getTestClass().getName());
}
#Override
protected List<Runner> getChildren() {
return fRunners;
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public static #interface WrappedRunner {
Class<? extends Runner> value();
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public static #interface ParameterSetter {
}
}
class WrappingRunner extends Runner {
private Runner wrappedRunner;
private Object[] parameters;
private Class<?> testClass;
private int testPosition;
public WrappingRunner(final Runner runner, final Object[] params, final Class<?> clazz, final int position) {
wrappedRunner = runner;
parameters = params;
testClass = clazz;
testPosition = position;
}
#Override
public Description getDescription() {
Description originalDescription = wrappedRunner.getDescription();
Description newDescription = Description.createSuiteDescription(nameFor(""), new Annotation[0]);
for (Description child : originalDescription.getChildren()) {
newDescription.addChild(decorateChildDescription(child));
}
return newDescription;
}
private String nameFor(String name) {
return String.format("%1$s[%2$s]", name, testPosition);
}
protected Description decorateChildDescription(final Description originalChildDescription) {
Description d = Description.createTestDescription(originalChildDescription.getTestClass(),
nameFor(originalChildDescription.getMethodName()),
originalChildDescription.getAnnotations().toArray(new Annotation[0]));
return d;
}
#Override
public void run(final RunNotifier notifier) {
try {
ParameterStorage.storeParameters(testClass, parameters);
wrappedRunner.run(notifier);
} finally {
ParameterStorage.clearParameters(testClass);
}
}
}
I have some test class to check if runner works. Runner works fine except tests are named weirdly. In eclipse it displays all tests and adds unrooted tests category
and surefire does not use my naming at all:
I compared description objects generated in my runner and in Parameterized runner, there seems to be no difference.

It's a bit ugly, but it's safer to pass the list of child runners to the parent constructor:
public ParameterizedWrapper(final Class<?> clazz) throws Throwable {
super(clazz, constructRunners(getParametersMethod());
}
private static List<Runner> constructRunners(final FrameworkMethod method)
throws Throwable {
...
You shouldn't need to override Suite.getChildren()

I have checked a bit more and found that description generated by my runner is ok. But that does not matter as it is inconsistent with description used during actual test execution. That is why eclipse shows entries as not executed and that is why surefire does not show my names.
Currently I think to use my own notifier to catch test start point and replace configuration at that point.
If someone has a better solution I would like to know about it :).

Related

JUnit to TestNG - #Rule in Superclass

I'm converting from JUnit to TestNG and facing a issue moving away from the #Rule annotation in JUnit.
In my superclass there is a #Rule, when I change this to #BeforeMethod it simply does not go into that method. (using that Println to confirm)
Also, when i do simply change #Rule or #ClassRule to #BeforeMethod, Eclipse complains that it is 'disallowed at this location'.
(Note I've removed some methods in the below to make the code length a little shorter/easier to view).
public abstract class AbstractTests
{
protected static boolean oneTimeSetUpComplete;
private static Logger log;
private static WebSessionFactory sessionFactory;
private static WcConfigManager config;
private WebSession session;
TestLogger testLogger = new TestLogger(getConfig(), getLog());
private StringBuilder errors = new StringBuilder();
protected WteDataProvider data;
#ClassRule
public static ExternalResource mainConfiguration = new ExternalResource() {
protected void before() throws Throwable {
setUpTests();
};
};
public Verifier errorCollector = new Verifier(){
#Override
protected void verify() throws Throwable {
failTestIfThereAreErrors();
};
};
public TestLogger getTestLogger() {
return testLogger;
}
#Rule
public RuleChain executionOrder() {
return RuleChain.outerRule(getTestLogger()).around(errorCollector);
}
#Rule
public TestRule dataReader = new TestRule() {
public Statement apply(final Statement base,
final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
System.out.println("PRINT IF YOU GO IN HERE");
DataProvider dataProvider = description.getAnnotation(DataProvider.class);
if (dataProvider == null) {
dataProvider = description.getTestClass().getAnnotation(DataProvider.class);
}
base.evaluate();
};
};
};
};
protected AbstractArgosTests(
Logger logger,
WcConfigManager configManager,
WebSessionFactory factory)
{
setUpTests(logger, configManager, factory);
}
}

How can I call Test class ctor with params?

I have unit test class and a static main entry method.
I know this is how I run the test class from my main method:
public class SingleJUnitTestRunner {
public static void main(String... args) throws ClassNotFoundException
{
String[] classAndMethod = args[0].split("#");
Request request = Request.method(Class.forName(classAndMethod[0]), classAndMethod[1]);
Result result = new JUnitCore().run(request);
System.exit(result.wasSuccessful() ? 0 : 1);
}
}
Is there a way to call a test-calls ctor with params and then run the tests?
I took a look at the Junit source code and came up with this:
public static void main(String... args) throws ClassNotFoundException {
String[] classAndMethod = args[0].split("#");
Object[] parameters = new Object[] {"constructor parameter"};
Class<?> className = Class.forName(classAndMethod[0]);
String methodName = classAndMethod[1];
Request request = createRequest(parameters, className, methodName);
Result result = new JUnitCore().run(request);
System.exit(result.wasSuccessful() ? 0 : 1);
}
private static Request createRequest(Object[] parameters, Class<?> className, String methodName) {
Description method = Description.createTestDescription(className, methodName);
return new ConstructorParameterRequest(className, parameters).filterWith(method);
}
Custom Request class so that we can use our own runner:
public class ConstructorParameterRequest extends Request {
private Class<?> clazz;
private Object[] parameters;
public ConstructorParameterRequest(Class<?> clazz, Object[] parameters) {
this.clazz = clazz;
this.parameters = parameters;
}
#Override
public Runner getRunner() {
try {
return new ConstructorParameterRunner(clazz, parameters);
} catch (Throwable e) {
return new ErrorReportingRunner(clazz, e);
}
}
}
Custom Runner class which creates the test class with constructor parameters. validateConstructor has to be overriden because BlockJUnit4ClassRunner checks for a zero argument constructor:
public class ConstructorParameterRunner extends BlockJUnit4ClassRunner {
private Object[] parameters;
public ConstructorParameterRunner(Class<?> clazz, Object[] parameters) throws InitializationError {
super(clazz);
this.parameters = parameters;
}
#Override
protected void validateConstructor(List<Throwable> errors) {
validateOnlyOneConstructor(errors);
}
#Override
protected Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(parameters);
}
}

I wish to run test cases based on the run mode declared in an excel

Please find the below codes and the query mentioned at the last.
**Annotation List**
public interface AnnotationList{
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface QCID {
String[] value();
}
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Author {
String value();
}
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Order {
int value();
}
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyTest {
static class None extends Throwable {
private static final long serialVersionUID = 1L;
private None() {
}}
JUnitLink
public class JunitLink extends BlockJUnit4ClassRunner {
// TODO work in test status to see if things should be run.
public static final Logger logger = LoggerFactory.getLogger(JunitLink.class);
public JunitLink(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
public void run(final RunNotifier notifier) {
JunitLink.super.run(notifier);
}
#Override
protected List<FrameworkMethod> computeTestMethods() {
List<FrameworkMethod> classMethods = getTestClass().getAnnotatedMethods(AnnotationList.MyTest.class);
SortedMap<Integer, FrameworkMethod> sortedTestMethodList = new TreeMap<Integer,FrameworkMethod>();
for (FrameworkMethod seleniumTest : classMethods) {
if (seleniumTest.getAnnotation(AnnotationList.Order.class) != null) {
sortedTestMethodList.put(seleniumTest.getAnnotation(AnnotationList.Order.class).value(),seleniumTest);
}
}
return new ArrayList<FrameworkMethod>(sortedTestMethodList.values());
}
#Override
protected void runChild(FrameworkMethod method, RunNotifier notifier) {
EachTestNotifier eachNotifier = makeNotifier(method, notifier);
if (method.getAnnotation(Ignore.class) != null) {
runIgnored(eachNotifier);
} else {
runNotIgnored(method, eachNotifier);
}
logger.info("Test {} run completed", method.getName());
}
private int runNotIgnored(FrameworkMethod method,EachTestNotifier eachNotifier) {
int failures = 0;
eachNotifier.fireTestStarted();
try {
methodBlock(method).evaluate();
}
catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
logger.error("Test {} failed!", method.getName());
failures++;
}
catch (Throwable e) {
eachNotifier.addFailure(e);
logger.error("Test {} failed!", method.getName());
failures++;
} finally {
eachNotifier.fireTestFinished();
}
return failures;
}
private void runIgnored(EachTestNotifier eachNotifier) {
eachNotifier.fireTestIgnored();
}
private EachTestNotifier makeNotifier(FrameworkMethod method,RunNotifier notifier) {
Description description = describeChild(method);
return new EachTestNotifier(notifier, description);
}}
Start Up Test
#RunWith(JunitLink.class)
public class StartUp extends SeleneseTestBase {
public static readProperties settings = new readProperties();
public static final Logger LOGGER = LoggerFactory.getLogger(INF.class);
public static WebDriver driver;
public static Actions actions;
#Override
#Before
public void setUp()
{
}
#Override
#After
public void tearDown() {
}
#BeforeClass
public static void StartBrowser() {
//Start Driver etc
}
#AfterClass
public static void tearClassDown() {
//Kill driver
}
}
//Test Cases Are Written Like These
#Author("XXXX")
#QCID({ "Smoke_TC01", "Smoke_TC02", "Smoke_TC03",
"TC04"})
public class SmokeTest extends Startup{
private Components component = new Components();
private String TestDataSheetName = "Smoke";
public SmokeTest() throws Exception {
}
#MyTest
#Order(1)
public void openHomepage() throws Exception {
component.openAPP();
}
#MyTest
#Order(2)
public void Login() throws Exception {
component.Login(USID, PWD);
}
#MyTest
#Order(3)
public void isTerminalLocked() throws Exception {
component.isTerminalLocked();
}
All the test method runs in order. Now I want to run only specific test cases which have runmode as "Yes" declared in a excel. I can add extraline before each test cases to read the lines from excel and run the particular test case but I want to read the excel and pass the selected testcases(based on runmode) to Junit runner.
Please help me.
I think your question is borderline "too broad". It's possible it may get closed for this reason.
Have a look at A JUnit Rule to Conditionally Ignore Tests. From that your isSatisfied() will have to parse your Excel. You can use something like Apache POI to do this.

java - reflection: How to Override private static abstract inner class method?

I have the following class:
class MyClass{
private static final int VERSION_VALUE = 8;
private static final String VERSION_KEY = "versionName";
public boolean myPublicMethod(String str) {
try {
return myPrivateMethod(str, VERSION_KEY, VERSION_VALUE,
new MyInnerClass() {
#Override
public InputStream loadResource(String name) {
//do something important
}
});
}
catch (Exception e) {
}
return false;
}
private boolean myPrivateMethod(String str, String key, int version,
ResourceLoader resourceLoader) throws Exception
{
//do something
}
private static abstract class MyInnerClass {
public abstract InputStream loadResource(String name);
}
}
I want to write unit test for myPrivateMethod for which I need to pass resourceLoader object and override it's loadResource method.
Here is my test method:
#Test
public void testMyPrivateMethod() throws Exception {
Class<?> cls = Class.forName("my.pack.MyClass$MyInnerClass");
Method method = cls.getDeclaredMethod("loadResource", String.class);
//create inner class instance and override method
Whitebox.invokeMethod(myClassObject, "testValue1", "testValue2", "name1", 10, innerClassObject);
}
Note, that I can't change code.
Well, you could use Javassist...
See this question. I haven't tried this, but you can call this method when you want the override:
public <T extends Object> T getOverride(Class<T> cls, MethodHandler handler) {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(cls);
factory.setFilter(
new MethodFilter() {
#Override
public boolean isHandled(Method method) {
return Modifier.isAbstract(method.getModifiers());
}
}
);
return (T) factory.create(new Class<?>[0], new Object[0], handler);
}
Well, the problem i see with your code is that you are calling myPublicMethod and you are giving fourth parameter as new MyInnerClass(). Now in your private method fourth parameter is given as ResourceLoader and from your code i see no relation between MyInnerClass and ResourceLoader. So you can try out following code. It might help.
Despite your warning that you cannot change the code i have changed it because i was trying to run your code.
class MyClass{
private static final int VERSION_VALUE = 8;
private static final String VERSION_KEY = "versionName";
public boolean myPublicMethod(String str) {
try {
return myPrivateMethod(str, VERSION_KEY, VERSION_VALUE,
new MyInnerClass() {
#Override
public InputStream loadResource(String name) {
return null;
//do something important
}
});
}
catch (Exception e) {
}
return false;
}
private boolean myPrivateMethod(String str, String key, int version,
MyInnerClass resourceLoader) throws Exception
{
return false;
//do something
}
private static abstract class MyInnerClass {
public abstract InputStream loadResource(String name);
}
}
Hope it helps.

ParameterizedTest with a name in Eclipse Testrunner

When you run a JUnit 4 ParameterizedTest with the Eclipse TestRunner, the graphical representation is rather dumb: for each test you have a node called [0], [1], etc.
Is it possible give the tests [0], [1], etc. explicit names? Implementing a toString method for the tests does not seem to help.
(This is a follow-up question to JUnit test with dynamic number of tests.)
I think there's nothing built in in jUnit 4 to do this.
I've implemented a solution. I've built my own Parameterized class based on the existing one:
public class MyParameterized extends TestClassRunner {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface Parameters {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface Name {
}
public static Collection<Object[]> eachOne(Object... params) {
List<Object[]> results = new ArrayList<Object[]>();
for (Object param : params)
results.add(new Object[] { param });
return results;
}
// TODO: single-class this extension
private static class TestClassRunnerForParameters extends TestClassMethodsRunner {
private final Object[] fParameters;
private final Class<?> fTestClass;
private Object instance;
private final int fParameterSetNumber;
private final Constructor<?> fConstructor;
private TestClassRunnerForParameters(Class<?> klass, Object[] parameters, int i) throws Exception {
super(klass);
fTestClass = klass;
fParameters = parameters;
fParameterSetNumber = i;
fConstructor = getOnlyConstructor();
instance = fConstructor.newInstance(fParameters);
}
#Override
protected Object createTest() throws Exception {
return instance;
}
#Override
protected String getName() {
String name = null;
try {
Method m = getNameMethod();
if (m != null)
name = (String) m.invoke(instance);
} catch (Exception e) {
}
return String.format("[%s]", (name == null ? fParameterSetNumber : name));
}
#Override
protected String testName(final Method method) {
String name = null;
try {
Method m = getNameMethod();
if (m != null)
name = (String) m.invoke(instance);
} catch (Exception e) {
}
return String.format("%s[%s]", method.getName(), (name == null ? fParameterSetNumber : name));
}
private Constructor<?> getOnlyConstructor() {
Constructor<?>[] constructors = getTestClass().getConstructors();
assertEquals(1, constructors.length);
return constructors[0];
}
private Method getNameMethod() throws Exception {
for (Method each : fTestClass.getMethods()) {
if (Modifier.isPublic((each.getModifiers()))) {
Annotation[] annotations = each.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.annotationType() == Name.class) {
if (each.getReturnType().equals(String.class))
return each;
else
throw new Exception("Name annotated method doesn't return an object of type String.");
}
}
}
}
return null;
}
}
// TODO: I think this now eagerly reads parameters, which was never the
// point.
public static class RunAllParameterMethods extends CompositeRunner {
private final Class<?> fKlass;
public RunAllParameterMethods(Class<?> klass) throws Exception {
super(klass.getName());
fKlass = klass;
int i = 0;
for (final Object each : getParametersList()) {
if (each instanceof Object[])
super.add(new TestClassRunnerForParameters(klass, (Object[]) each, i++));
else
throw new Exception(String.format("%s.%s() must return a Collection of arrays.", fKlass.getName(), getParametersMethod().getName()));
}
}
private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception {
return (Collection<?>) getParametersMethod().invoke(null);
}
private Method getParametersMethod() throws Exception {
for (Method each : fKlass.getMethods()) {
if (Modifier.isStatic(each.getModifiers())) {
Annotation[] annotations = each.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.annotationType() == Parameters.class)
return each;
}
}
}
throw new Exception("No public static parameters method on class " + getName());
}
}
public MyParameterized(final Class<?> klass) throws Exception {
super(klass, new RunAllParameterMethods(klass));
}
#Override
protected void validate(MethodValidator methodValidator) {
methodValidator.validateStaticMethods();
methodValidator.validateInstanceMethods();
}
}
To be used like:
#RunWith(MyParameterized.class)
public class ParameterizedTest {
private File file;
public ParameterizedTest(File file) {
this.file = file;
}
#Test
public void test1() throws Exception {}
#Test
public void test2() throws Exception {}
#Name
public String getName() {
return "coolFile:" + file.getName();
}
#Parameters
public static Collection<Object[]> data() {
// load the files as you want
Object[] fileArg1 = new Object[] { new File("path1") };
Object[] fileArg2 = new Object[] { new File("path2") };
Collection<Object[]> data = new ArrayList<Object[]>();
data.add(fileArg1);
data.add(fileArg2);
return data;
}
}
This implies that I instantiate the test class earlier. I hope this won't cause any errors ... I guess I should test the tests :)
JUnit4 now allows specifying a name attribute to the Parameterized annotation, such that you can specify a naming pattern from the index and toString methods of the arguments. E.g.:
#Parameters(name = "{index}: fib({0})={1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
A code-less though not that comfortable solution is to pass enough context information to identify the test in assert messages. You will still see just testXY[0] failed but the detailed message tells you which one was that.
assertEquals("Not the expected decision for the senator " + this.currentSenatorName + " and the law " + this.votedLaw,
expectedVote, actualVote);
If you use JUnitParams library (as I have described here), the parameterized tests will have their stringified parameters as their own default test names.
Moreover, you can see in their samples, that JUnitParams also allows you to have a custom test name by using #TestCaseName:
#Test
#Parameters({ "1,1", "2,2", "3,6" })
#TestCaseName("factorial({0}) = {1}")
public void custom_names_for_test_case(int argument, int result) { }
#Test
#Parameters({ "value1, value2", "value3, value4" })
#TestCaseName("[{index}] {method}: {params}")
public void predefined_macro_for_test_case_name(String param1, String param2) { }
There's no hint that this feature is or will be implemented. I would request this feature because it's nice to have.

Categories

Resources