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);
}
}
Related
I am trying to achieve Singleton Instance with Abstract class in Java. I have read like implementing it as a LazyLoad is the best practice. I could not make it as I am not much used to this pattern and even Java.
getInstance() is always null, I am not sure why?
I don't think this follows lazy loading as the instance is constructed.
Any additional comments are welcome apart from this as I am completely new to Java and worked on c# before.
Here is what I have,
Interface:
public interface IConditionAppender{
public String Append();
}
Abstract
public abstract AppenderBase {
private static IConditionAppender instance;
protected AppenderBase(IConditionAppender instance)
{
this.instance = instance;
}
public static IConditionAppender getInstance(){ return instance; }
}
Implementation
public final class AndAppender extends AppenderBase implements IConditionAppender {
private AndAppender()
{
super(new AndAppender())
}
#Override
public String Append()
{
return " AND ";
}
}
Test
System.out.println(AndAppender.getInstance().Append());
Here is how AndAppender can be implemented
public final class AndAppender implements ConditionAppender {
private static final AndAppender instance;
public static AndAppender getInstance() {
if (instance == null)
instance = new AndAppender();
return instance;
}
private AndAppender() { }
#Override
public String append() {
return " AND ";
}
}
The same approach for OrAppender etc.
Note: this implementation is not thread-safe.
A bit simpler way is to use Enum which is singleton by default and can implement interfaces.
public enum Appender implements ConditionAppender {
AND(" AND "), OR(" OR ");
final String operation;
Appender(String operation) {
this.operation = operation;
}
#Override
public String append() {
return operation;
}
public static void main(String[] args) {
System.out.println(AND.append());
System.out.println(OR.append());
}
}
The code below may help you~
public abstract class AbstractSingleton {
private static Map<String, AbstractSingleton> registryMap = new HashMap<String, AbstractSingleton>();
AbstractSingleton() throws SingletonException {
String clazzName = this.getClass().getName();
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
synchronized (registryMap) {
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
registryMap.put(clazzName, this);
}
}
}
}
#SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz) throws InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
T instance = clazz.newInstance();
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
public static AbstractSingleton getInstance(final String clazzName)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (!registryMap.containsKey(clazzName)) {
Class<? extends AbstractSingleton> clazz = Class.forName(clazzName).asSubclass(AbstractSingleton.class);
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
AbstractSingleton instance = clazz.newInstance();
return instance;
}
}
}
return registryMap.get(clazzName);
}
#SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz, Class<?>[] parameterTypes, Object[] initargs)
throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InvocationTargetException, InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
Constructor<T> constructor = clazz.getConstructor(parameterTypes);
T instance = constructor.newInstance(initargs);
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
static class SingletonException extends Exception {
private static final long serialVersionUID = -8633183690442262445L;
private SingletonException(String message) {
super(message);
}
}
}
From: https://www.cnblogs.com/wang9192/p/3975748.html
I want to do a factory pattern in java with generics. My code is:
The interface:
public abstract class Factory<T> {
public abstract T create();
}
FactoryA class:
public class FactoryA extends Factory<FactoryA> {
public FactoryA() {
}
public FactoryA create() {
return new FactoryA();
}
}
FactoryB class:
public class FactoryB extends Factory<FactoryB> {
public FactoryB() {
}
public FactoryB create() {
return new FactoryB();
}
}
The main class:
public class FactoryCreator {
public static <T> T createFactory() {
Factory<T> t = ?; // is that right way?
return t.create();
}
public static void main(String[] args) {
FactoryA factoryA = FactoryCreator.createFactory();
FactoryB factoryB = FactoryCreator.createFactory();
}
}
The question, what Factory t = need to be equal, or is there any other way?
Not really sure what you're trying to achieve, but this might help;
public interface Factory<T>
{
public T create(String type);
public T create(String type, Object arg);
public T create(String type, Object[] args);
}
And then have a class implement that factory interface, like this;
public class TemplateFactory<T> implements Factory {
#Override
public T create(String type) throws IllegalArgumentException
{
return create(type, null);
}
#Override
public T create(String type, Object arg) throws IllegalArgumentException
{
// Convert to array of 1 element
Object[] arguments = new Object[1];
arguments[0] = arg;
return create(type, arguments);
}
#Override
public T create(String type, Object[] args) throws IllegalArgumentException
{
// Create array for all the parameters
Class<?> params[] = (args != null) ? new Class<?>[args.length] : new Class<?>[0];
if(args != null)
{
// Adding the types of the arguments
for(int i = 0; i < args.length; ++i)
params[i] = (args[i] != null) ? args[i].getClass() : null;
}
try
{
// Create a class variable
Class classLoader = Class.forName(type);
// Find the right constructor
Constructor co;
if(params.length > 0)
co = classLoader.getConstructor(params);
else
co = classLoader.getConstructor();
// Instantiate the class with the given arguments
T newObject = (T)co.newInstance(args);
return newObject;
}
catch(Exception e)
{
throw new IllegalArgumentException(e.toString());
}
}
}
And then use it like this (using some imaginary strategy-classes as an example):
TemplateFactory<StrategyInterface> factory;
factory = new TemplateFactory<>();
factory.create("packageName.StrategyA");
factory.create("packageName.StrategyB");
factory.create("packageName.StrategyC");
The strategy classes (A, B and C) would implement the StrategyInterface-class in this example.
Something like this might work:
public static <T extends Factory> T createFactory(Class<T> clazz) {
try {
t = clazz.newInstance();
return t.create();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
...
FactoryA factoryA = FactoryCreator.createFactory(FactoryA.class);
alternatively, without parameters. But then you need two methods.
public static FactoryA createFactoryA() {
return new FactoryA().create();
}
...
FactoryA factoryA = FactoryCreator.createFactoryA();
Since the Generic types are erased at runtime you have to supply the Class parameter so that the runtime knows what class you are talking about.
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 :).
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.
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.