I'm writing unit tests for my Java app and I need to write a test for a potential JiBX exception that can be thrown. The method I'm testing calls on a method from another class, where the JiBX exception can be potentially thrown. This is the class I'm testing (let's call it Class A):
#Inject
private CommonDAL commonDAL;
#Async
public Future<String> getTransactionalXXXAvailability(
List<XXXAvailRequestEntry> requestEntries, TravelWindow travelWindow) {
if (requestEntries.size() == 0)
return null;
XXXAvailRqAccessor requestAccessor = new XXXAvailRequestBuilder().buildRequest(requestEntries, travelWindow);
logger.info(requestAccessor.marshalRequest());
String responseAsXml = null;
try {
responseAsXml = getResponse(requestAccessor.getRequest());
} catch (JiBXException e) {
logger.error("Problem unmarshaling the XXX avail response: ", e);
}
logger.info(responseAsXml);
return new AsyncResult<String>(responseAsXml);
}
private String getResponse(OTAXXXAvailRQ request) throws JiBXException {
HbsiConnectionInfo connectionInfo = new HbsiConnectionInfo();
connectionInfo.useConnectionInfoFromContext();
HBSIXML4OTAWebserviceSoap hbsiSoap = getHbsiSoapService(connectionInfo);
InterfacePayload header = new InterfacePayload();
header.setChannelIdentifierId("XXXXXXXXX");
header.setVersion("2005B");
header.setInterface("HBSI XML 4 OTA");
ComponentInfo componentInfo = new ComponentInfo();
XXXAvailRqAccessor requestAccessor = new XXXAvailRqAccessor(request);
componentInfo.setId(requestAccessor.getFirstXXXCode());
componentInfo.setUser( connectionInfo.getUsername() );
componentInfo.setPwd( connectionInfo.getPassword() );
componentInfo.setComponentType(EComponentType.XXX);
Login login = new Login();
login.setComponentInfo(componentInfo);
Message body = new Message();
// todo: this needs to be unique for every request.
// todo: hook up to logging
body.setRequestId(UUID.randomUUID().toString());
body.setTransaction(ETransaction.XXX_AVAIL_RQ);
body.setXML(requestAccessor.marshalRequest());
return hbsiSoap.getSoapRequest(header, body, login);
}
HBSIXML4OTAWebserviceSoap getHbsiSoapService(HbsiConnectionInfo connectionInfo) {
HBSIXML4OTAWebservice ws = new HBSIXML4OTAWebservice( connectionInfo.getWsdlLocation() );
HBSIXML4OTAWebserviceSoap hbsiSoap = ws.getHBSIXML4OTAWebserviceSoap();
Map<String, Object> requestContext = ((BindingProvider)hbsiSoap).getRequestContext();
String readTimeout = commonDAL.getPropertyValue(new PropertyKey(Section.HBSI,
Property.HBSI_WS_READ_TIMEOUT));
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, Integer.parseInt(readTimeout));
String connectionTimeout = commonDAL.getPropertyValue(new PropertyKey(Section.HBSI,
Property.HBSI_WS_CONNECTION_TIMEOUT));
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, Integer.parseInt(connectionTimeout));
return hbsiSoap;
}
The method that throws the error is as follows (and from another class, let's call it Class B):
public String marshalRequest() {
StringWriter requestAsXml = new StringWriter();
try {
IBindingFactory bindingFactory = BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);
IMarshallingContext marshalingContext = bindingFactory.createMarshallingContext();
marshalingContext.setIndent(2);
marshalingContext.setOutput(requestAsXml);
marshalingContext.marshalDocument(request);
} catch (JiBXException e) {
logger.error("Problem marshaling PROTECTEDCLASSNAME.", e);
}
return requestAsXml.toString();
}
When "body.setXML(requestAccessor.marshalRequest());" is called, another class (requestAccessor) is visited by the test, and it's method .marshalRequest is where the JiBX exception is supposed to be thrown. The purpose of the tests I'm writing is to get this Class A's unit test coverage to 100&, but the system under test is composed of at least two classes as I can't mock XXXAvailRqAccessor object called requestAccessor. I can't get any tests to produce this error, for the following reasons.
The XXXAvailRqAccessor object called requestAccessor is instantiated inside the methods I'm testing so I can't use a mock to throw an exception.
the OTAXXXAvailRQ argument passed to .getResponse() cannot be mocked because it's created by the builder for XXXAvailRqAccessor.
I tried spying on IBindingFactory, but it didn't work. I created a method in Class B that would instantiate an IBindingFactory so I could spy on it, but that didn't work.
I also tried using PowerMock to return a mock XXXAvailRqAccessor when it is instantiated, however when I attempted to mock a JiBXExceptioin for .getRequest, Mockito said "Checked exception is invalid for this method". If I can't get Mockito to throw this error, I don't know if it's possible to manipulate the associated objects to throw it.
Well not really, or I don't know of such way at least. You could, if you REALLY want to do it (I'm against it) create a method like this in that class:
IBindingFactory getBindingFactory() {
return BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);
}
And replace this line:
IBindingFactory bindingFactory = BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);
With:
IBindingFactory bindingFactory = getBindingFactory();
Then you can spy() (you can read on Mockito.spy() in the documentation if you're not familiar with it) this object and make this method return a mock. From that point it's smooth sailing.
This approach is not adviced though because:
you are creating a new method (a useless one) just for testing
said method has to be visible for testing so you cannot mark it as private...
I'm not a huge fan of spies in general
The question remains: how to properly test such cases. Well in most situations I try to refactor as much as possible and sometimes it helps. And in other cases... Well I still did not come up with a better solution.
As I said in my comment, I fully advocate Mateusz's solution. But there is an alternative. In the class that has the marshalRequest method, have a private final field of type IBindingFactory. Also in this class, have a package-private constructor with one extra argument, that is, the IBindingFactory to set. The normal constructor will call BindingDirectory.getFactory( ... ) then call the new constructor. So, if the standard constructor has a single String argument, the class might look like this.
public class MyClass{
private String name;
private IBindingFactory bindingFactory;
public MyClass(String name){
this(name, BindingDirectory.getFactory(PROTECTEDCLASSNAME.class));
}
MyClass(String name, IBindingFactory bindingFactory){
this.name = name;
this.bindingFactory = bindingFactory;
}
public String marshalRequest() {
StringWriter requestAsXml = new StringWriter();
try {
IMarshallingContext marshalingContext = bindingFactory.createMarshallingContext();
marshalingContext.setIndent(2);
marshalingContext.setOutput(requestAsXml);
marshalingContext.marshalDocument(request);
} catch (JiBXException e) {
logger.error("Problem marshaling PROTECTEDCLASSNAME.", e);
}
return requestAsXml.toString();
}
}
The reason for doing this is so that in the test for your class, you can create a mock IBindingFactory, and pass it in to the package-private constructor.
Related
So I have written a code that looks like this :
public ClassA myMethod(param1) {
ClassB myObject;
//START of code block #1
try {
myObject = tryToGetObject(param1);
if (myObject == null) {
return new ClassA("it's null");
}
} catch (ParamNotValidException e) {
return new ClassA("param1 is not valid");
}
//END of code block #1
/**
Here do a lot of things with myObject
*/
return new classA(myObject.toString());
}
The thing is, I have a lot of very similar code to code block #1 and I would like to refactor all that. The problem is that this code block can either return :
myObject, which I will use later to build a ClassA object to return
OR
directly a ClassA object.
NB:
ClassB id not a subclass of ClassA
I used String as ClassA constructor parameters for the example but the real code is not using Strings.
I'd like to get something that kind of looks like this :
public ClassA method(param1) {
ClassB myObject;
//START of code block #1
getMyObjectOrReturnClassAObject();
//END of code block #1
/**
Here do a lot of things with myObject
*/
return new classA(myObject.toString());
}
I tried to look into java Optional but i'm not sure if and how I could use this here.
Some context to clarify :
This code is about returning Java Play Result. For example when a user asks for a specific object using an exposed API, it performs some tests about the user's permissions, the validity of the request, and other things. If one test fails, It returns a play.Result with the appropriate HTTP.Status, error code, error message and so on. If each test passes, It returns a json representation of the requested object along with HTTP 200 status.
You already suggested going with Optional, which is a good direction here.
First of all, modify tryToGetObject(param1) to return Optional<Object> while using either Optional.of() or Optional.ofNullable(). Then you can do the following:
myObject = tryToGetObject(param1).orElse(new ClassA("it's null"));
You could wrap that in another method to get rid of the exception:
private Object getMyObjectOrReturnClassAObject(Object param1) {
try {
return tryToGetObject(param1).orElse(new ClassA("it's null"));
catch(ParamNotValidException e) {
return new ClassA("param1 is not valid");
}
}
I have a class called Price with constructor, which I am dynamically loading via reflection:
public Price(Context context, String pair) {
this.context = context;
this.value1 = pair.substring(0, 3);
this.value2 = pair.substring(3, 6);
this.dps = context.getService().getm1(value1, value2).getm2();
}
However I want to mock the Context object
and I want
context.getService().getm1(value1, value2).getm2()
to return 5.
Here is what I have tried
//mocking the Context class
Class<?> contextClass = urlClassLoader.loadClass("com.algo.Context");
constructor =contextClass.getConstructor();
Object context = Mockito.mock(contextClass);
//trying to instantiate the Price class
Class<?> priceClass = urlClassLoader.loadClass("com.algo.Price");
constructor = priceClass.getConstructor(contextClass,String.class);
Mockito.when(context.getService().getm1(value1, value2).getm2().thenReturn(5));
Object price = constructor.newInstance(context,"PRICES");
However I have a red line under
context.getService()
The error says
The method getService() is undefined for the type Object
How can I get around this, my end goal is to create the Price object with the variable
dps
being an int 5, that is why I want to mock the Context object.
For me the only way is to implement your whole test using reflection which is really laborious especially in your case as you will need to do the same thing for each method call as you cannot mock directly context.getService().getm1(value1, value2).getm2().
Assuming that I have a class Context as below
public class Context {
public int getm1(String value1, String value2) {
return -1;
}
}
A normal test case would be:
#Test
public void normal() throws Exception {
Context context = Mockito.mock(Context.class);
Mockito.when(context.getm1(Mockito.anyString(), Mockito.anyString())).thenReturn(5);
Assert.assertEquals(5, context.getm1("foo", "bar"));
}
The same test using reflection would be:
#Test
public void reflection() throws Exception {
... // Here I get the classloader
// Get the class by reflection
Class<?> contextClass = urlClassLoader.loadClass("com.algo.Context");
// Mock the class
Object context = Mockito.mock(contextClass);
// Get the method by reflection
Method method = contextClass.getMethod("getm1", String.class, String.class);
// Invoke the method with Mockito.anyString() as parameter
// to get the corresponding methodCall object
Object methodCall = method.invoke(context, Mockito.anyString(), Mockito.anyString());
// Mock the method call to get what we expect
Mockito.when(methodCall).thenReturn(5);
// Test the method with some random values by reflection
Assert.assertEquals(5, method.invoke(context, "foo", "bar"));
}
Cannot really understand this issue. If you are working with an unknown type it cannot be typed as Context within the construtor.
But independently, an approach would be to create interfaces representing the expected structure of context and then mock the interfaces to return the value.
It is not necessary to really load the dynamic class within the test if it is mocked either way.
I am testing a private method using JUnit and I am invoking it using Reflection. The error I am getting is java.lang.InstantiationException. I know it is not creating an instance of Class but I am not sure what I am doing wrong. Object object = clazz.newInstance(); is the line that throws Exception.
Method under test
private int _getType(String type) {
if ("DATE".equalsIgnoreCase(type)) return Types.DATE;
if ("STRING".equalsIgnoreCase(type)) return Types.VARCHAR;
if ("INT".equalsIgnoreCase(type)) return Types.INTEGER;
if ("TIMESTAMP".equalsIgnoreCase(type)) return Types.TIMESTAMP;
return Types.NULL;
}
JUnit test
#Test
public void testGetType() throws Exception {
String type1 = "DATE";
String type2 = "STRING";
String type3 = "INT";
String type4 = "TIMESTAMP";
Class clazz = SpringStoredProcImpl.class;
Object object = clazz.newInstance();
Method method = object.getClass().getDeclaredMethod("getType", String.class);
method.setAccessible(true);
method.invoke(object, type1);
I don't have my asserts yet so please ignore it.
Thanks in advance.
You try to create an instance with a no argument constructor which does exist in your case.
As the constructors are public you should first create your object normally using the new keyword, then execute the rest of your code starting from Method method...
FYI, if you wanted to create your object by reflection it would be something like clazz.getConstructor(DataSource.class, String.class, ArrayList.class).newInstance(dataSource, sprocName, params) instead of simply clazz.newInstance()
Different answer: don't do that.
Why do you think you need to make this method private? It looks like the responsibility of this method is to "lookup" an enum type, based on string input. I think it would make much more sense to simply make this method package protected and avoid the reflection overhead/hassle.
I want to avoid the constructor calling during object creation in java (either default constructor or user defined constructor) . Is it possible to avoid constructor calling during object creation???
Thanks in advance......
Simply extract the intialization logic that you want to avoid into another method called init. You can not avoid calling exactly one constructor.
No matter what pattern or strategy you use, at some point your will need to call a constructor if you want to create an object.
Actually, its possible under some circumstances by using classes from the JVM implementation (which do not belong to the JRE API and are implemenation specific).
One example here http://www.javaspecialists.eu/archive/Issue175.html
It should also be possible using sun.misc.Unsafe.allocateInstance() (Java7)
Also, the constructor is apparently bypassed when using the clone()-method to create a copy of an object (and the class doesn't override clone to implement it different from the Object.clone() method).
All of these possibilities come with strings attached and should be used carefully, if at all.
You can mock the constructors of a class. They will still be called, but not executed. For example, the following JUnit+JMockit test does that:
static class CodeUnderTest
{
private final SomeDependency someDep = new SomeDependency(123, "abc");
int doSomething(String s)
{
someDep.doSomethingElse(s);
return someDep.getValue();
}
}
static final class SomeDependency
{
SomeDependency(int i, String s) { throw new RuntimeException("won't run"); }
int getValue() { return -1; }
}
#Test
public void mockEntireClassIncludingItsConstructors()
{
new NonStrictExpectations() {
#Mocked SomeDependency mockDep;
{ mockDep.getValue(); result = 123; }
};
int result = new CodeUnderTest().doSomething("testing");
assertEquals(123, result);
}
I've been looking into Java reflections. This is an example from Wikipedia http://en.wikipedia.org/wiki/Reflection_(computer_programming):
// Without reflection
new Foo().hello();
// With reflection
Class<?> cls = Class.forName("Foo");
cls.getMethod("hello").invoke(cls.newInstance());
I find this a bit counter-intuitive because the method is called before creating an instance.
Reflections of course could be useful to call game leves, especially if there are hundreds of them.
EDIT - SOME SOLUTIONS:
Here is a simple example of reflection which works on Android:
try {
Class<?> clazz = Class.forName("com.test.Foo");
clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
and the class file
public class Foo {
Foo(){
hello();
}
private void hello() {
Log.e("FOO", "Hello!");
}
}
Suppose one wants to call an Activity by reflection:
Activity activity;
try {
Class<?> clazz = Class.forName("com.test.MyLevelActivity");
activity = (Activity) clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
startActivity(new Intent(this,activity.getClass()));
Suppose a level which contains data and methods should be 'loaded' by reflection:
Level currentLevel;
try {
Class<?> clazz = Class.forName("com.test.Level_1_1");
currentLevel = (Level) clazz.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
String levelName = currentLevel.getLevelName();
String result = Integer.toString(currentLevel.processData(3, 7));
Toast.makeText(this, levelName + " result= " + result, Toast.LENGTH_LONG).show();
Here are the classes:
public abstract class Level {
public abstract String getLevelName();
public abstract int processData(int a, int b);
}
public class Level_1_1 extends Level{
private String levelName = "level 1.1";
public String getLevelName(){
return levelName;
}
public int processData(int a, int b) {
return a * b;
}
}
I find this a bit counter-intuitive because the method is called before creating an instance
Sorry, don't think so. The method arguments are first evaluated before being passed to "invoke" and hence you end up passing a "new" instance of the Foo class to the "invoke" method of the Method class. Also, in case you are wondering why call "invoke" on method object, it's because for a given class, you'd create the Method objects only once and all subsequent invocations would rather depend on the "state" of the object rather than the "method" being invoked.
here
foo.hello();
can't work, foo is just an object that does not have a method hello().
Things that are unfamiliar may seem counter-intuitive, but eventually new idioms become natural. Just go with the standard approach.
To understand it, consider that the method definition is not part of the object, you write the method once for the class, it "lives" independently of any given object. Hence it's quite reasonable for the class to say "hey method, apply yourself in the context of this object, he's one of us"
It's not really clear what you mean, but does this help?
Class<?> cls = Class.forName("Foo");
Method method = cls.getMethod("hello");
Object instance = cls.newInstance();
method.invoke(instance);
you are not calling the method first. you are just definig the method and then invoking it. also, the instance of cls is created before we actually enter invoke. I find the reflections to be a very useful API in java and it is used by almost all the framworks that work on java like struts, log4j, etc. In reflection you always define the method you wanna call and only then work on the actual object you wanna operate on.
Hope this helps!