Unit test with wrapped public static method Java - java

I am not very familiar with Unit Tests, I know that they are very important for code quality, and I want to write some in my project. I recently run into some issues. The context is that, I am writing the testClassA for my Aclass, but some functions in Aclass depend on BClass.
BClass is a utility function, so it has many public static function.
AClass uses Bclass's functions :
public class Aclass{
public boolean Afunction()
{
String result = Bclass.Bfunction();
//do stuff with result
return true
}
}
public class Bclass{
public static String Bfunction()
{
//function code
}
}
I want that everytime the BClass.Bfunction is called, then I can return what I want without really execute the real Bfunction in Bclass, so my Aclass doesn't depend on other class in my test. Is it possible ?

One approach that limits your changes to just the Aclass, and eliminates the dependency on Bclass (as you asked for) is extract-and-override:
Identify the code you wish to bypass in your test and extract it to a method.
Override that method in a sub-class of your class-under test. In this overidden method, you can code whatever mock behavior is appropriate for the test:
So your modified Aclass would look like this:
public class Aclass {
public boolean Afunction() {
String result = doBfunction();
// do stuff with result
return true;
}
// This is your "extracted" method.
protected doBfunction() {
return Bclass.Bfunction();
}
}
and your test class would look like this:
class AClassTest {
#Test
public void testAFunction() {
Aclass testObject = new TestableAclass();
boolean value = testObject.AFunction();
// now you can assert on the return value
}
class TestableAclass extends Aclass {
#Override
protected String doBfunction() {
// Here you can do whatever you want to simulate this method
return "some string";
}
}
}

Related

Java method simulation

As part of behavioral testing I need to simulate the method call in a given class.
So say if I have a class like:
class A {
public void abc(){
new classB().getData();
}
public void xyz( boolean callabc){
if (callabc) {
abc();
}
}
So my requirement is to first find all methods in class A then find which method is making which call like xyz is calling abc which is calling class B getData method.
Is it possible to get all these data in Java?
You can transform your code into something like this:
public class A {
private final ClassB b;
public A(ClassB b) {
this.b = b;
}
public void abc(){
b.getData();
}
public void xyz( boolean callabc){
if (callabc) {
abc();
}
}
}
Then you can pass mock implementation of class B during tests. Then you can verify that some method was invoked on mock with specific parameters with mockito library:
http://static.javadoc.io/org.mockito/mockito-core/2.3.0/org/mockito/Mockito.html#1

How to make Superclass Method returns instance of SubClass

I have a class called Test and a class called SubTest who extends Text, I would like to have a method in the Test class who will returns the instance of SubTest when called, I would like to do :
SubTest test = new SubTest().setTest("Hello!").setOtherTest("Hi!");
The setTest() and setOtherTest() methods should be in the Test class.
But when I do :
public Test setTest(String test) { return this; }
It only returns the instance of Test so I have to cast Test to SubTest, but I don't want to.
Is it possible ? If yes, how ?
Thanks, MinusKube.
Having a method return its owner (this) to be able to 'chain' multiple method calls is called fluent API. You can solve your problem by using generics, although the resulting code might be somehow less readable though:
public class Person<T extends Person<T>> {
public T setName(String name) {
// do anything
return (T)this;
}
}
public class Student extends Person<Student> {
public Student setStudentId(String id) {
// do anything
return this;
}
}
public class Teacher extends Person<Teacher> {
public Teacher setParkingLotId(int id) {
// do anything
return this;
}
}
Now, you do not need any casts:
Student s = new Student().setName("Jessy").setStudentId("1234");
Teacher t = new Teacher().setName("Walter").setParkingLotId(17);
See also: Using Generics To Build Fluent API's In Java
It is possible to have those methods return a SubTest, because Java's return types are covariant.
You must override those methods so that you can return this, a SubTest, in SubTest, e.g.:
#Override
public SubTest setTest(String message) {
super.setTest(message); // same functionality
return this;
}

Mocking getClass method with PowerMockito

I'd like to avoid mocking the getClass() method for a class but cannot seem to find any way around it. I'm trying to test a class that stores objects class types in a HashMap to a particular method to be used later. A brief example of this is:
public class ClassToTest {
/** Map that will be populated with objects during constructor */
private Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
ClassToTest() {
/* Loop through methods in ClassToTest and if they return a boolean and
take in an InterfaceA parameter then add them to map */
}
public void testMethod(InterfaceA obj) {
final Method method = map.get(obj.getClass());
boolean ok;
if (method != null) {
ok = (Boolean) method.invoke(this, obj);
}
if (ok) {
obj.run();
}
}
public boolean isSafeClassA(final ClassA obj) {
// Work out if safe to run and then return true/false
}
public boolean isSafeClassB(final ClassB obj) {
// Work out if safe to run and then return true/fals
}
}
public interface InterfaceA {
void run()
}
public class ClassA implements InterfaceA {
public void run() {
// implements method here
}
}
public class ClassB implements InterfaceA {
public void run() {
// implements method here
}
}
I then have a JUnit test that looks a little like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassA.class})
public class ClassToTestTest {
private final ClassToTest tester = new ClassToTest();
#Test
public void test() {
MockGateway.MOCK_GET_CLASS_METHOD = true;
final ClassA classA = spy(new ClassA());
doReturn(ClassA.class).when(classA).getClass();
MockGateway.MOCK_GET_CLASS_METHOD = false;
tester.testMethod(classA);
verify(classA).run();
}
}
My problem is although inside the test() method classA.getClass(); will return ClassA, once inside tester's testMethod() method it still returns the ClassA$EnhancerByMockitoWithCGLIB$... class and so my object useful will always be null.
Is there any way I can get around mocking the class or what do I need to do to fix this?
Thanks in advance.
Your problem is actually that getClass is final in Object, so you can't stub it with Mockito. I can't think of a good way around this. There is one possibility, that you might consider.
Write a utility class that has a single method
public Class getClass(Object o){
return o.getClass();
}
and refactor the class that you're testing, so that it uses an object of this utility class, instead of calling getClass() directly. Then, make it possible to inject the utility object, either with a special package-private constructor, or with a setter method.
public class ClassToTest{
private UtilityWithGetClass utility;
private Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
public ClassToTest() {
this(new UtilityWithGetClass());
}
ClassToTest(UtilityWithGetClass utility){
this.utility = utility;
// Populate map here
}
// more stuff here
}
Now, in your test, make a mock of the object and stub getClass. Inject the mock into the class that you're testing.
Wow, what a headache to get this code testable. The main issues are that you can't use mock objects as key objects into your calls to map.get(obj.getClass()), and you're trying to invoke() potentially mock objects for your testing. I had to refactor your class under test so that we can mock out the functionality/behaviour and be able to verify its behaviour.
So this is your new implementation to be tested with member variables decoupling the various pieces of functionailty and injected by the test class
public class ClassToTest {
MethodStore methodStore;
MethodInvoker methodInvoker;
ClassToInvoke classToInvoke;
ObjectRunner objectRunner;
public void testMethod(InterfaceA obj) throws Exception {
Method method = methodStore.getMethod(obj);
boolean ok = false;
if (method != null) {
ok = methodInvoker.invoke(method, classToInvoke, obj);
}
if (ok) {
objectRunner.run(obj);
}
}
public void setMethodStore(MethodStore methodStore) {
this.methodStore = methodStore;
}
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
}
public void setObjectRunner(ObjectRunner objectRunner) {
this.objectRunner = objectRunner;
}
public void setClassToInvoke(ClassToInvoke classToInvoke) {
this.classToInvoke = classToInvoke;
}
}
This is your test class that no longer requires PowerMock, because it can't mock the Method class. It just returns a NullPointerException.
public class MyTest {
#Test
public void test() throws Exception {
ClassToTest classToTest = new ClassToTest();
ClassA inputA = new ClassA();
// trying to use powermock here just returns a NullPointerException
// final Method mockMethod = PowerMockito.mock(Method.class);
Method mockMethod = (new ClassToInvoke()).getClass().getMethod("someMethod"); // a real Method instance
// regular mockito for mocking behaviour
ClassToInvoke mockClassToInvoke = mock(ClassToInvoke.class);
classToTest.setClassToInvoke(mockClassToInvoke);
MethodStore mockMethodStore = mock(MethodStore.class);
classToTest.setMethodStore(mockMethodStore);
when(mockMethodStore.getMethod(inputA)).thenReturn(mockMethod);
MethodInvoker mockMethodInvoker = mock(MethodInvoker.class);
classToTest.setMethodInvoker(mockMethodInvoker);
when(mockMethodInvoker.invoke(mockMethod,mockClassToInvoke, inputA)).thenReturn(Boolean.TRUE);
ObjectRunner mockObjectRunner = mock(ObjectRunner.class);
classToTest.setObjectRunner(mockObjectRunner);
// execute test method
classToTest.testMethod(inputA);
verify(mockObjectRunner).run(inputA);
}
}
The additional classes you require are as follows
public class ClassToInvoke {
public void someMethod() {};
}
public class ClassA implements InterfaceA {
#Override
public void run() {
// do something
}
}
public class ClassToInvoke {
public void someMethod() {};
}
public class MethodInvoker {
public Boolean invoke(Method method, Object obj, InterfaceA a) throws Exception {
return (Boolean) method.invoke(obj, a);
}
}
public class MethodStore {
Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
public Method getMethod(InterfaceA obj) {
return map.get(obj);
}
}
Put all this into your IDE and it will pass with a Green bar...woohoo!
I've faced with similar question, too. I think you should add ClassToTest.class to #PrepareForTest, because you want to mock the getClass() function in that class

Mocking a call on a public method of an abstract class without subclassing the abstract Class, using mockito prefererably

I am writing an unit testing using JUNIT + Mockito to test a method like :
public someObject methodUnderTest(){
SomeObject obj = SomeAbstractClass.someMethod();
if(obj!=null){
obj.someOtherMethod();
}
return someThing;
}
And I would like to mock the call on abstract Class "SomeAbstractClass" mentioned in above code fragment so i can verify call on "obj" like :
verify(SomeAbstractClass).someMethod();
verify(obj).someOtherMethod();
I have tried using mockito features like :
Mockito.CALLS_REAL_METHODS
Mockito.RETURNS_MOCKS
but they don't work due to dependencies not available to the SomeAbstractClass.
Note:
1) SomeObject is an Interface.
2) I need a technique to test above code fragment. I am constrained to use the above code fragment and cannot change the code fragment.
You can use PowerMock to mock static and final methods.
It sounds like the problem is that your use of CALLS_REAL_METHODS is applying to the entire class, where you really want to mock out specific methods (i.e. make a "partial mock"). You have two options here, one using thenCallRealMethod, and one using CALLS_REAL_METHODS and then specifically mocking the calls you need:
public void testMethodUnderTest_mockSpecificThings() {
SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class);
SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
when(myAbstractClass.someMethod()).thenReturn(foo);
when(myAbstractClass.methodUnderTest()).thenCallRealMethod();
myAbstractClass.methodUnderTest();
verify(myAbstractClass).someMethod();
verify(myObject).someOtherMethod();
}
public void testMethodUnderTest_makeSpecificRealCalls() {
SomeAbstractClass myAbstractClass =
Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS);
SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
// overrides the default answer
when(myAbstractClass.someMethod()).thenReturn(myObject);
myAbstractClass.methodUnderTest();
verify(myAbstractClass).someMethod();
verify(myObject).someOtherMethod();
}
Be forewarned that SomeAbstractClass is never actually instantiated, so if you rely on any behavior in the abstract class constructor, like variable initialization--including inline initialization where the fields are declared--you will need to make those calls explicitly yourself.
Assumption: if you write unit test, I guess you still can modify tested method a bit.
Solution:
extract static method call to overridable method:
public someObject methodUnderTest() {
SomeObject obj = getSomeObject();
if(obj!=null){
obj.someOtherMethod();
}
return someThing;
}
protected SomeObject getSomeObject() {
return SomeAbstractClass.someMethod();
}
then you can use Mockito Spy to partially mock the object you actually test:
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
classUnderTest= new ClassUnderTest();
classUnderTest = Mockito.spy(classUnderTest);
}
#Test
public void test() {
SomeObject someObject = Mockito.mock(SomeObject.class);
when(classUnderTest.getSomeObject()).thenReturn(someObject);
classUnderTest.methodUnderTest();
verify(someObject).someOtherMethod();
}
#Test
public void testNull() {
when(classUnderTest.getSomeObject()).thenReturn(null);
classUnderTest.methodUnderTest();
verify(something);
}
Use anonymous classes:
public interface SomeObject {
public Object someOtherMethod();
}
public abstract class SomeAbstractClass {
abstract SomeObject someMethod();
}
#Test
public void test() {
SomeAbstractClass target = new SomeAbstractClass() {
SomeObject someMethod() {
// some impl
SomeObject someObject = new SomeObject() {
public Object someOtherMethod() {
// some other impl
}
};
return someObject;
}
};
// now test target
}

Mock a static method multiple times using JMockit within a JUnit test

I have a class with static methods that I'm currently mocking with JMockit. Say it looks something like:
public class Foo {
public static FooValue getValue(Object something) {
...
}
public static enum FooValue { X, Y, Z, ...; }
}
I have another class (let's call it MyClass) that calls Foo's static method; I'm trying to write test cases for this class. My JUnit test, using JMockit, looks something like this:
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
new Expectations() {
{
Foo.getValue((Object) any); result = Foo.FooValue.X;
}
};
}
myClass.doSomething();
}
This works fine and dandy, and when the test is executed my instance of MyClass will correctly get the enum value of Foo.FooValue.X when it calls Foo.getValue().
Now, I'm trying to iterate over all the values in the enumeration, and repeatedly run the test. If I put the above test code in a for loop and try to set the result of the mocked static method to each enumeration value, that doesn't work. The mocked version of Foo.getValue() always returns Foo.FooValue.X, and never any of the other values as I iterate through the enumeration.
How do I go about mocking the static method multiple times within the single JUnit test? I want to do something like this (but obviously it doesn't work):
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
for (final Foo.FooValue val : Foo.FooValue.values() {
new Expectations() {
{
// Here, I'm attempting to redefine the mocked method during each iteration
// of the loop. Apparently, that doesn't work.
Foo.getValue((Object) any); result = val;
}
};
myClass.doSomething();
}
}
}
Any ideas?
Instead of "mocking the method multiple times", you should record multiple consecutive return values in a single recording:
public class MyClassTest extends TestCase
{
#Test
public void testMyClass(#Mocked Foo anyFoo)
{
new Expectations() {{
Foo.getValue(any);
result = Foo.FooValue.values();
}};
for (Foo.FooValue val : Foo.FooValue.values() {
myClass.doSomething();
}
}
}
It could also be done with a Delegate, if more flexibility was required.

Categories