Replacing a java method invocation from a field with a method call - java

I am trying to build a mocking framework in java which fits to a specific requirement of a project.
The scenario is, I have a method
public String returnRandom(){
String randomString = this.randomGenerator.returnRandom()
}
The randomGenerator is a dependency of this class and is injected to the object only in runtime. Means it would be null if the object is created without the dependency injection framework.
During an isolation test, I want the replace assignment to the statement
this.randomGenerator.returnRandom();
with a method which returns a stray random value, say "Helloworld".
I was trying to use javassist.expr.FieldAccess for the same, using which I can replace the field to a no operation and method call can be modified using javassist.expr.MethodCall.
I am not able to figure out how to replace the field with a dummy or a no operation. Is this possible using java assist or should I go for a more low level bytecode manipulation like asm?
Note:
I could achieve replacing of a method call which doesn't originate on a field using javassist.expr.MethodCall. For example if the above example is
public String returnRandom(){
String randomString = returnRandom();
}
I am able to replace as
public String returnRandom(){
String randomString = MockedString.getSampleRandom();
}

The best thing you can do is to create an interface for the random generator, say:
public interface RandomGenerator {
public String returnRandom();
}
Then your original random generator can implement this interface, and the class that uses a random generator can depend on a class with a RandomGenerator interface.
Once you have this, it is fairly straight-forward to test. You create a mock generator that does what you want:
public class MockRndGenerator implements RandomGenerator {
public String returnRandom() {
return "Helloworld";
}
}
and when you're testing, you inject this class instead of the original.
public class Demo {
public Demo (RandomGenerator rndGenerator) {
this.randomGenerator = rndGenerator;
}
public String returnRandom(){
String randomString = this.randomGenerator.returnRandom()
}
}
* UPDATE *
Since I can't add code in comments, here is the Mockito solution:
you can always use Mockito to avoid creating physical mocks, and then you can set up expectations and inspections on the way
class Test {
public static rndTest() {
RandomGenerator rnd = Mockito.mock(RandomGenerator.class);
Mockito.when(rnd.returnRandom()).thenReturn("Helloworld");
Demo = new Demo(rnd);
}
}

I could solve the problem using javassist.expr.MethodCall. Below is the expression editor class used for checking the feasibility.
This replaces the targetMethod call (methodcalltoReplace) with the code used to get a mock object.
new ExprEditor() {
#Override
public void edit(MethodCall m) throws CannotCompileException {
try {
if (m.where().getName().equals(sourceMethod)) {
if (m.getMethod().getName().equals(methodcalltoReplace)) {
if(lineNumberOfMethodcalltoReplace == m.getLineNumber()){
// The content of the hardcoded string can be replaced with runtime data
m.replace("$_ = ($r)"+"new com.nuwaza.aqua.sample.SampleForMethodInvocationFieldAccess().helloworld();");
}
}
}
} catch (NotFoundException e) {
e.printStackTrace();
}
super.edit(m);
}
For a detail documentation see,
Javaassist tutorial, introspection and customization

One approach I have done in the past is to create a back door static method to replace your random generator with a mocked version. You can then use mockito to instruct what it should return. By making it static you avoid having to create many of them, just one for the whole class. Like anything else it has pros and cons but it might fit your specific need.
Instead of called the field directly, like you are in your example, you could use a method instead getRandGen(). That method would either use the local random generator or the mocked static one if it is set.
Essentially this is a back door to overwrite your dependency framework's chosen object with one you select yourself at runtime during unit testing and it is static so it affects the whole class and not only specific instantiations.

Related

Access private method of an instance in unit test

I came across the following issue when I was trying to unit test my code. If I have a class that creates an instance and for example a getter method like this:
public class Test {
private static Test instance;
private ArrayList<String> arrayList = new ArrayList<String>();
public static Test getInstance() {
return instance;
}
private ArrayList<String> getArrayList() {
return arrayList;
}
}
If now I want to access the arrayList in a test case it would fail, because the list is returned by a non-accessable private method. So trying something like this wouldn't work:
public class AccessTest {
private Test test;
public void accessList(){
test = Test.getInstance();
test.getArrayList();
}
}
So one way to access the arrayList anyway, would probably be to change the visibility to protected. But isn't there a better way to access the method? Is it really necessary to make a method protected only because of a test that needs to access it?
In general, if you have some private methods in your class and you feel that you have problems with testing them, it is a sign of a bit of a code smell. It shows that too many functionality is hidden behind private wall.
You could change visibility of such method to package protected, so JUnit test will see it. There is also a Google Guava annotation #VisibleForTesting or something like that. But again - this is a sign of wrong class design.
Think of extracting such method to a separate class and make that methods public then.
For example, take a look at the following code:
class ReportCreator {
public File createSomeImportantReport(LocalDate date) {
String fileName = provideFileName(date);
File result = new File(fileName);
return result;
}
private String provideFileName(LocalDate date) {
// ... some complex business logic to generate file name based on date... ;)
return fileName;
}
}
There is a private method provideFileName() that does some complicated things and let's say it's hard to test if you would test only createSomeImportantReport().
See what changes if you externalize that functionality.
class ReportCreator {
private FileNameProvider fileNameProvider;
public File createSomeImportantReport(LocalDate date) {
File result = new File(fileNameProvider.provideFileName(date));
return result;
}
}
class FileNameProvider {
public String provideFileName(LocalDate date) {
return ......;
}
}
You now have option to test that thing separately, focus on what's important in that particular case.
Despite the fact that I don't see a use case for a private getter, you can use the package private access level. This is the default access level so you don't have to specify it. You can then test it by adding the test class in the same package name in the test directory. For instance the class is located in src/main/java/application and the test class can then be located in src/test/java/application.
Use Java Reflection for that:
Test test = new Test();
Method getArrayListMethod = test.getClass().getDeclaredMethod("getArrayList", null);
getArrayListMethod.setAccessible(true);
ArrayList<String> list = (ArrayList<String>) getArrayListMethod .invoke(test);
System.out.println(list); // Prints the list
Create your Test object, use the method getClass() and get the method declared on that class by its name.
Then set that method accessible dynamically. If you know the data type that it returns, then cast it to it.

JUnits for constructors which uses third party API call

Below mentioned is the class that I need to test:
public class MyClass {
private String key;
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
}
public String getKey() {
return key;
}
}
Now I need to test this constructor, but am unable to mock this Third party API call. And the Test case would be as mentioned below :
public class MyClassTest{
#Test
public void test1(){
MyClass c = new MyClass(dummyconnection);
assertNotNull(c.getKey != null);
}
}
But this case would be giving me an error that ThirdPartyAPI Class is failing as the the connection object is mocked.
So I want to mock this ThirdPartyApi call. Is it possible using Easymock, powermock?
Simple: EasyMock does not support mocking static calls. So you can turn to PowerMock(ito) or JMockit in case you do not want to change your code.
But the better approach would be to understand that using static always leads to tight coupling between your classes, and that you want to make sure that this doesn't affect your ability to unit test your code.
In your case:
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
simply replace that with:
public MyClass(Connection con) {
this (ThirdPartyApi.getkey(con));
}
/** unit testing only */
MyClass(Key key) {
...
And voila, you got a constructor that you can call from your unit test - and now you simply pass a mocked key object. And your tests will no longer execute that static call - because you use the key-taking constructor in all your tests.
But you probably want another test case to make sure that calling the public constructor does what you expect it to do - and that could be to throw an exception because that static call fails.
Beyond that: I fully agree with the comments - the fact that your constructor is doing so much (including static calls) has a certain design smell on it.

Create a stub of 3rd party Java library

My task is to create stubs for a 3rd party Java library that our application will make calls to. My problem is how to define the class of the method "return type" (if that's the correct Java terminology). I don't have access to the full documentation of the 3rd party API, just a list of methods. For now, my stubs just need to return true/false or 1/0, whatever
Here's an example of one method to illustrate. This is what I have been given
OobResponse RequestOobRequest(
String ClientName,
String SecurityLink,
short LenofHHU,
RequestMode RequestMode)
I have no idea what OobResponse or RequestMode are supposed to be, but I should still be able to create stubs, right?
So far, this is all I have.
public class stubber {
public class OobResponse {
public int someVar;
}
public class RequestMode {
public int someVar;
}
public OobResponse RequestOobRequest(
String ClientName,
String SecurityLink,
short LenofHHU,
RequestMode RequestMode)
{
OobResponse oobr = new OobResponse();
return oobr;
}
}
The documentation you have is weird, since variable and method names do not hold Java convention of using camelCase. Also, what you seem to be ordered to do would hold minimal later use. However, the way I understand your problem you could do:
create new package for all classes you will be stubbing. That will be relevant later
actually stub stuff. That is, for every class in the documentation that is not built into java create the class. I assumed that what you wrote is a method declaration (made most sense to me, though it could also be a constructor or whatever), it needs to be a part of some class, I called it "Unknown" below. Replace that name with actual class name.
For your example you would need:
public class RequestMode {
}
public class OobResponse {
}
public class Unknown {
public OobResponse RequestOobRequest(
String ClientName,
String SecurityLink,
short LenofHHU,
RequestMode RequestMode){
return new OobResponse(); // or null, whatever since it is a stub
}
}
Note, that when stubbing you do not create any additional variables (like someVar you tried to add), ONLY what API allows you to access (only classes and public methods within would be a good rule of a thumb). You could also use interfaces instead of classes, it would be cleaner, but there are legitimate reasons not to (when you want a code with new StubbedClass() to compile for example).
Now, in your actual code you (or someone) will be able to use your stubs like the actual library:
public class YourBusinessClass{
public OobResponse getOobByClientName(String clientName){
return new Unknown().RequestOobRequest(clientName,...);
}
}
When you get the actual library you can replace imports from stub package in your actual code that uses it to the actual library package.
That is the only usefull way of using stubs like that I could think of, so I hope that is what you want.
One possibility (academically at least) is to use a facade to the actual 3rd party library. You could probably create a class which has the methods that you need and your main code calls this class in place of the the 3rd party library, include all the methods that you need and return 1/0 etc., when the library is available dispatch the calls to the library from the facade.
However, there is a fair bit of caution, if the actual data model of the library is complex you could end up replicating all of them or their equivalent in your code, if it is not (like simple strings etc.) then this approach would work.
With reference to the comment below for en example, i am adding the following:
Let us say we have a class:
public class Class0{
public String method0(String arg0){return "from Method 0";}
public String method1(String arg0, String arg1){return "from Method 1";}
}//class closing
Now let us say we only have the signature for the above class and not the class itself, then we can do the following (for now):
public Class0Facade{
public String method0(String arg0){return "from Method 0";}
public String method1(String arg0, String arg1){return "from Method 1";}
}//class closing
Rest of your code can use the 'class0Facade' class and go ahead.
When the actual Class0 is available, you would change Class0Facade, in the following way:
public Class0Facade{
protected Class0 deligate;
public Class0Facade(){delegate=new Class0();}
public String method0(String arg0){return delegate.method0(arg0);}
public String method1(String arg0, String arg1){return delegate.method(arg0, arg1);}
}//class closing
Rest ot four code does not need to change
Maybe you could go with classes that extend the stubbed classes:
public class Stubber extends StubbedClass {
public OobResponse RequestOobRequest(
String ClientName,
String SecurityLink,
short LenofHHU,
RequestMode RequestMode) {
OobResponse oobr = new OobResponse();
return oobr;
}
}
If you cant create an OobResponse, you could similarly create a public class OobResponseStub extends OobResponse

Unit testing without dependency injection

Code from Spring in Action :
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnightTest {
#Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
BraveKnight knight = new BraveKnight(mockQuest);
knight.embarkOnQuest();
verify(mockQuest, times(1)).embark();
}
}
I understand the use of dependency injection, which allows us to switch implementation without modifying the depending code.
The book says "terribly difficult to write a unit test ...".
However, I am not able to understand how it will be very difficult for unit-testing without dependency injection! My intuition refuses to co-operate !
Can you start writing junit/unit testing for the class "DamselRescuingKnight" and for any other better example class (without DI), to make me realize the point/stage at which DI makes unit testing easier ?
The difficulty in your above example comes when you try to test DamselRescuingKnight. Assume, you want to test that one (see below)
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class DamselRescuingKnightTest {
#Test
public void knightShouldEmbarkOnQuest() {
DamselRescuingKnight knight = new DamselRescuingKnight ();
knight.embarkOnQuest();
// now what?
}
}
how can you be sure that knight.embarkOnQuest() does actually do anything? The answer is that you can't because you can't access the quest instance it uses internally.
Now in order to be able to test such a class, you would add a getQuest() method to the Knight, and then also add a isEmbarked() method to Quest.
It is also quite fair to say, that this example is very simple, because the knight only calls the quest without parameters, and nothing else. If knight would interact with a quest and also get some weaponary from a Blacksmith, then you would also somehow need to allow access for that. You could probably do all the boilerplate to get that done. But then assume, you're passing parameters to blacksmith - how do you ensure that the passed parameters were correct? Or how do you ensure that the knight gets his/her weapon before going to the quest?
This is where dependency injection comes to the rescue. you can just create mocks (either by using a mock framework, or by implementing your own mocks) so that you can verify that your knight does the expected things.
The problem is of course the quest variable. You want to somehow check that the embark() method is invoked. Without being able to replace it with a mocked instance, this is very hard.
If the variable were protected instead of private, the test case could overwrite it by virtue of living in the same package.
You can also use Aspect-Oriented Programming to replace the variable.
But the easiest is if the code is written with dependency injection from the get-go.
You ask to see how AOP can be used. The following is an example of an AspectJ pointcut that you can use in a unit test to replace the RescueDamselQuest instance with a mocked one called MockRescueDamselQuest (apologies if I don't get the syntax exactly right, it has been a while since I used AspectJ):
aspect MockRescueDamselQuestInstantiations {
RescueDamselQuest around (): call(RescueDamselQuest.new()) {
return new MockRescueDamselQuest();
}
}
This will catch any instantiations of RescueDamselQuest (i.e. calls to new RescueDamselQuest()) and return a MockRescueDamselQuest object instead.
Given how much more wiring this requirest, I'd strongly suggest using dependency injection instead!
This perplexed me as well when I was reading this in Spring in Action. After reading above answers I wanted to add that when DI is not used then Junit method need to call method of object which is private (which is in accessible) and this object Quest is created in constructor of DamselRescuingKnight so test case for embarkQuest() can't be written. On contrary when using DI then you are externalizing object creation and Junit method can create that object so it will be accessible to it then can test emabarkQuest() which eventually need to test quest method

Using methods from a subclass on an object that is an instance of the superclass

Let's say there's a class that I use extensively and is returned by a method.
CommonClass obj = getCommonObject();
Now I want to extend this class to create some utility method to avoid repeating myself.
public CommonClassPlus extends CommonClass {
public String dontRepeatYourself() {
// the reason I'm creating a subclass
}
}
Of course I would like to use my improved class for the method above, however, downcasting isn't allowed.
CommonClassPlus obj = getCommonObject();
//Cannot cast to CommonClassPlus
How can I use the method dontRepeatYourself() if I can only work with the object that is an instance of the superclass?
CommonClass and getCommonObject() are from an external library and I cannot change them.
You cannot add behavior to an existing instance in Java (like you could in JavaScript, for example).
The closest you can get in Java is the Decorator pattern:
CommonClassPlus obj = decorate(getCommonObject());
where decorate() is
public CommonClassPlus decorate(CommonClass x) {
return new CommonClassPlus(x);
}
This approach creates a potentially huge amount of boilerplate because it must delegate each method call to the wrapped instance. If a method in CommonClass is final and there is no interface you can reimplement, then this approach fails altogether.
In most cases you will be able to get along with a simple static helper method:
public static String dontRepeatYourself(CommonClass x) {
...
}
If CommonClass is from an external library, you probably want to wrap it in an Adapter Pattern anyway, using the principle of Composition over Inheritance.
This gives you complete control if you want to, say, change the library you're using, and allows you to add functionality like dontRepeatYourself().
public class CommonClassAdapter implements MyAdapter {
private final CommonClass common;
private final String cachedResult;
// Note that I'm doing dependency injection here
public CommonClassAdapter(CommonClass common) {
this.common = common;
// Don't expose these because they shouldn't be called more than once
common.methodIOnlyCallOnce();
cachedResult = common.anotherMethodIOnlyCallOnce();
}
#Override
public void someMethod() {
common.someMethodWithDifferentName();
}
#Override
public String dontRepeatYourself() {
return cachedResult;
}
}
Note also that most modern IDEs have things like Eclipse's Source -> Generate Delegate Methods to make this process faster.

Categories