Automating unit test cases in java - java

Referred this question first. But seems my context is different.
I'll try to be short and simple. (Just the code I'm putting out is quite big ;)
I have some 50+ service classes. And need to write the unit test cases for all of them.
Across all these test classes, some tests are common. (delete, find etc) Just the object type would differ across the service classes.
Following example would clear the picture.
Consider following service class which has CRUD operations.
public class ObjService {
public Obj addObj(ParamType param, String var) { ... }
public void deleteObj(ParamType param, String var) { ... }
public List<Obj> findAllObj(ParamType param, String var) { ... }
public Obj findById(ParamType param, String var, String objIdToFind) { .. }
public List<Obj> getAllObjs(ParamType param, String var, ObjQuery objQuery) throws Exception { ... }
public Obj updateObj(ParamType param,
String var, Obj objToUpdate) throws Exception { }
}
Now I'm writing a test case for ObjService class. (Test Framework - testNG)
public class ObjServiceTest {
//These methods which will differ across all service classes
#Test
public void testAddObj() throws Exception {
addObj();
}
#Test
public void testUpdateObj() throws Exception {
Obj objToUpdate = addObj();
Obj updatedObj = updateObj(objToUpdate);
}
public Obj addObj() throws Exception {
//add obj test data and return the obj object
}
public Obj updateObj(Obj objToUpdate) throws Exception {
//update obj test data and return the updated obj object
}
//Following methods will be common to all classes. Except the name 'obj'
//e.g. For obj2 it would change to testDeleteObj2() { Obj2 obj2Todelete.... etc}
#Test
public void testDeleteObj() throws Exception {
Obj objToDelete = addObj();
deleteObj(objToDelete);
}
public void deleteObj(Obj objToDelete) throws Exception {
//delete the obj object
}
#Test
public void testFindById() throws Exception {
ObjService client = new ObjService();
List<Obj> objs = dsClient.findAllObj(...);
}
#Test
public void testFindAllObjs() throws Exception {}
#Test
public void testGetObjs() throws Exception {}
}
Now. Writing the common methods manually for all classes is surely a time consuming job. So can it be reduced by doing some automation?
(Tried my best to put the question in least baffling way)
Edit: 1) The test classes already inherit a BaseTestClass which contains the initial setup needed. So that is a problem.
2) Please don't forget the part, where
refactoring is needed across the
methods which differ.

It sounds like your services should implement some generic interface. That way you could write an abstract base test case which is also generic, then make each "real" service test inherit from it, including inheriting the tests within that abstract class.
The constructor for the subclass would pass in the appropriate values for things like the service, a sample query etc.
EDIT: For the base class, just make the abstract base test class subclass your existing base class.
For specialization, either override the test method itself when it needs to do a completely different thing, or make the test methods depend on abstract methods in the abstract class, so that each concrete subclass can fill in the appropriate behaviour.

A good first step would be to make a base Test class which handles the common methods, and then derive specific Test classes from that base class to test the methods which differ per service.
You could make the base Test class a generic class which takes your service objects as a generic parameter. You may want or need to make your service classes implement a common interface, so that you can test the common methods in a consistent, type-safe manner.

Create an abstract class that contains all tests that are common to all Services.
Include abstract method definitions for the methods that have to be implemented differently in each test class.
Now create all your test classes as subclass of this abstract class, implementing only what's needed for the individual Service.

One possible solution could be to genericize your test cases with the object type as generic type parameter. Possibly having a generic base test class, and instantiating it with the needed concrete type(s) in each separate test subclass. I did it in a somewhat similar case and it worked out well.
Eventually, if you have much duplicated functionality to test, consider refactoring your tested classes (possibly using generics as well) to eliminate duplication. However, write the unit tests first to ensure that you aren't breaking anything during the refactoring.

Related

Run same Junit Test with multiple objects derived from same interface

I am trying to improve my knowledge about testing I'm trying to achieve running the same JUnit test class with different objects derived from the same interface.
so we can assume the following:
interface Base {
void sort();
}
class A implements Base {
#Override
public void sort() {
//sort naively
}
}
class B implements Base {
#Override
public void sort() {
//sort using another better approach
}
}
class C implements Base {
#Override
public void sort() {
//sort using optimized approach
}
}
class Test {
#Test
void test1() {
Base obj = new A();
obj.sort();
obj.otherStuff();
}
}
class SecondTest {
//trying to avoid making multiple test classes that has only one line in difference
#Test
void test1() {
var obj = new B();
obj.sort();
obj.otherStuff();
}
So my question is how to run the test class with the objects from A,B,C without falling into the trap of duplicate code and redundancy?
Please note that I wrote this example just to illustrate my point, and the sort() doStuff() methods are just placeholders but when you have over ~70 line of code duplication in each test class it starts to look ugly and redundant.
*I have looked at #beforeEach, #Before, #After and I don't think I see a way where those might help me.
You can write a parameterized test with a MethodSource.
#ParameterizedTest
#MethodSource("bases")
void test1(Base obj) {
obj.sort();
obj.otherStuff();
}
static Stream<String> bases() {
return Stream.of(new A(), new B(), new C());
}
A way to fix it is the following, you create a method within your test class that takes as input the Base obj and contains all the duplicate lines. What you'll do then is to initialize the obj in different tests, then pass it to the method.
Here is a code that would do the job:
class Test {
#Test
void test1() {
Base obj = new A();
wrapperMethod(obj);
}
#Test
void test2() {
var obj = new B();
wrapperMethod(obj);
}
public static void wrapperMethod(Base obj){
obj.sort();
obj.otherStuff();
}
}
As a rule of thumb, testing can be much like normal programming where redundancy is avoided with methods to guarantee reusability.
Cheers,
D
First of all you have to fix your understanding of what UnitTesting is about.
UnitTesting is not about code (coverage).
UnitTesing is about verifying desired public behavior where "public behavior means return values and/or communication with dependencies.
Each test method should verify a single atomic assumption of the tested units desired behavior.
From this point of view it does not make sense to pass a bunch of objects sharing the same interface trough the same test method since these different interface implementations exist to implements the interfaces methods with their own unique behavior. In turn the assumption how the objects behave differ uniquely.
If all the objects where expected to behave identically (which is the only assumption a single test method could verify) there where no different objects (i.e. implementations) in the first place.

Java - How to test the non-abstract methods of an abstract class?

I have an abstract class that features no abstract methods... How would one go about testing this? Can I simply import it into a test class and go about business as usual?
Example:
public abstract class SomeAbstractClass implements SomeOtherClass {
// Some variables defined here
private static final String dbUrl = System.getProperty("db.url");
// Some public methods
public String doSomethingToUrl(String url) {
url = url + "/takeMeSomewhereNice";
}
}
Say I pass in an arg for db.url of localhost:8080, and I wanted to test that the doSomethingToUrl method did output the new string... Would it still be in this format?
public class TestUrl {
SomeAbstractClass sac = new SomeAbstractClass();
#Test
public void testUrlChange() throws Exception {
String testUrl = "localhost:8080";
assertThat("localhost:8080/takeMeSomewhereNice",
sac.doSomethingToUrl(testUrl));
}
}
You wouldn't be able to create an instance of just SomeAbstractClass, no - but you could create an anonymous subclass:
private SomeAbstractClass sac = new SomeAbstractClass() {};
You may well want to create a concrete subclass just for the sake of testing though - so that any time you do add abstract methods, you just need to put them there.
While I suspect you could use a mocking framework for this, I suspect it would add more complexity for little benefit, unless you need to check under what situations the abstract methods are called. (Mocks are great for interaction testing, but can be brittle for other purposes.) It could easily make for more confusing error messages (due to the infrastructure involved) as well.
You cannot initialize an abstract class, so your test class wouldn't compile as is.
You can either use an anonymous instance (the example below should suffice):
SomeAbstractClass sac = new SomeAbstractClass(){};
However, I would actually recommend you mock the class by means of a mocking framework such as Mockito or EasyMock.

How do I mock invocations to methods in super class using jMockit

I have a scenario in which I have to mock a method in parent class. The method is invoked from the method under test. I have not been able to mock the function using jMockit.
My super class is method is as follows
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
My subclass is as follows
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
I have tried using partial mocks using jMockit's tutorial, but it has not worked for me. My test method is given below.
UPDATE: I implemented Rogerio's suggestion as follows. The implementation still calls the real method. When I debug the instance of mocked class in Eclipse, this is what I see com.project.web.mvc.$Subclass_superClass#6b38c54e
#Test
public void testMethodUnderTest(#Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
The issue is that when I try to mock the invocation of emailRecipients, it always tries to call the actual function. I am using Java 7, jMockit v1.35, and Maven 3x for our builds.
UPDATE The code is legacy code. As a result, we can't update it. We can not use PowerMock as it is not among the libraries that have been approved by the company. We can use either jMockit or Mockito or a combination of both.
The fact that you want to mock the method from parent class shows that your approach fails the Separation of Concerns/Single responsibility Pattern (SoC/SRP).
The use of PowerMock as suggested by Rajiv Kapoor is possible but this (as any use of PowerMock) would be a surrender to bad design.
You can solve your design problem by applying the Favor Composition over Inheritance principle (FCoI).
To do so you'd change your (most likely) abstract super class into a "normal" class. You'd create an interface that declares all the public and abstract methods in your super class. Your child class would no longer extend the parent class but implement the interface. It would get an instance of the former parent class as dependency and call it's methods providing common behavior as needed.
This dependency can easily mocked without the need of PowerMock.
UPDATE The code is legacy code. As a result, we can't update it.
In that case you are outruled.
The code you have is not unittestable because it is written in an untestable way. Your only chance is to write module and/or acceptance tests (without the use of a mocking framework) covering each and every execution path through your code.
This test will be expensive to create and slow but they will gurad your when refactoring the code to something testable (== changable) later.
see below example
P.S. use Mockito.any(HttpServletRequest.class)instead of Mockito.any(ArrayList.class) for your code
Super Class
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
Test Class
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
#Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
#Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
If you don't want the code in emailRecipients to execute then use doNothing()
else use doAnswer to execute some other code

How to mock an object created via Class.newInstance(className)?

I'm trying to add unit tests to some legacy code that has a String class name passed to it and that creates an object implementing a particular handler interface using Class.newInstance(String className). I can control the class name I'm passing, I can get a pointer to the new handler object (via a getHandler() call), and I would like to observe calls to it using Mockito.
My current solution is:
Create a new test class TestHandler that implements the interface.
Have that test class contain a Mockito mock object that also implements the interface.
Manually pass through all the interface methods to the mock object.
Make the mock object accessible via a getMock() method.
Observe the object by making verify() calls to objectUnderTest.getHandler().getMock().
This works, but feels a little inelegant, especially having to manually write all the pass-thru methods.
Is there a better solution?
Fundamentally, you're running into the same problems as trying to test a newly-created instance using new; the Class.newInstance (probably properly Class.forName(foo).newInstance()) doesn't hurt you, but doesn't help you either.
As a side note, your TestHandler sounds like a general purpose delegate implementation, which sounds pretty useful anyway (particularly if you ever need to write a Handler wrapper). If it is, you might want to promote it to be adjacent to your Handler in your production code tree.
Though I recognize that you mention legacy code, this becomes very easy if you are allowed to refactor to include a testing seam. (Ignoring reflective exceptions here for ease of explanation.)
public ReturnType yourMethodUnderTest(String className) {
return yourMethodUnderTest(Class.newInstance(className));
}
/** Package private for testing. */
public ReturnType yourMethodUnderTest(Handler handler) {
return yourMethodUnderTest(Class.newInstance(className));
}
You could also extract the object creation and replace it in your test:
/** Instance field, package-private to replace in tests. */
Function<String, Handler> instanceCreator =
( x -> (Handler) Class.forName(x).newInstance());
public ReturnType yourMethodUnderTest(String className) {
Handler handler = instanceCreator.apply(className);
// ...
}
You could even just extract it to a method and replace it in your test:
public ReturnType yourMethodUnderTest(String className) {
Handler handler = createHandler(className);
// ...
}
/** Package private for testing. */
Handler createHandler(String className) {
return Class.forName(className).newInstance();
}
#Test public void yourTest() {
// Manually replace createHandler. You could also use a Mockito spy here.
ObjectUnderTest objectUnderTest = new ObjectUnderTest() {
#Override Handler createHandler(String className) {
return mock(Handler.class);
}
}
// ...
}
Side note: Even though Mockito creates a named dynamic type, you almost certainly will not be able to hack it in and allow your code to create it by name. This is because the call to mock registers the instance within Mockito's internal state.
// BAD: Unlikely to work
#Test public void yourTest() {
objectUnderTest.methodUnderTest(
mock(Handler.class).getClass().getName());
// ...
}
Create a public method where you will place the logic to fetch the newInstance of the class
ClassA objectClassA=createNewInstance(className);
likewise,and
public ClassA createInstance(String className){
return (ClassA) (Class.forName(className)).newInstance();
}
Now suppose we were creating an instance of classA inside of ClassB
then in TestClass of B, we can simply mock this createInstance method
doReturn(mockClassA).when(mockClassB).createInstance(className);

Get method invocated inside a method in Java

I want to make a JUnit test to assure that some classes don't use a specific set of methods (from another classes). Example
class MyClass
{
void myMethod()
{
otherClass.otherClassStaticMethod();
}
}
class myTest
{
void test()
{
assertFalse(CalledMethods.getMethodsCalledBy("myClass.myMethod").Contains("otherClass.otherClassStaticMethod"));
}
}
In this test I want to assure that myMethod doesn't invocate otherClassStaticMethod. How can I find what methods are being called inside a method in compile time (ignore methods called using reflection)? I thought about a .java parser, do you recommend any?
you can mock "otherClass" and verify that the method isn't invoked. E.g. using Mockito you can even specify in which order what methods are supposed to be invoked (under the condition their instances are mocks) and specify which methods are not allowed to be invoked
as coding.mof said, to mock static methods you should use PowerMock/PowerMockito:
example:
PowerMockito.mockStatic(OtherClass.class);
PowerMockito.verifyStatic(never());
OtherClass.otherClassStaticMethod();
It sounds like you should be using a mock library and let that handle it all for you. I'd recommend JMock as my library of choice. If you're using instance methods then this would be perfect for you - if, as your example shows, it's static methods then PowerMock may work*1.
With JMock, you'd have something like:
public class MyClass {
public MyClass(Dependency dependency) {
this.dependency = dependency;
}
void myMethod() {
dependency.someMethod();
}
}
#RunWith(JMock.class)
public class MyTest {
private Mockery context = new Mockery();
#Test
public void doesNotCallSomeMethod() {
Dependency dependency = context.mock(Dependency.class);
MyClass obj = new MyClass(dependency);
obj.myMethod(); <--- this will fail fast
}
}
When you call obj.myMethod, JMock will instantly report that you never said dependency should have any methods called. It will also tell you what method you DID call and what parameters you passed in if any
*1 I don't use PowerMock as I steer away from static methods unless they are pure functions

Categories