Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Thursday, September 7, 2017

Random Beans

There are many instances while writing test cases, where we wanted a baked object with some default values, which we then modify partially as per the need for the test.
Random beans exactly achieves this

I have a Pnl object which has PnlKey. For my test, I need test data with different key elements - date, book, account, etc - so that I can check if the aggregation on those levels works perfectly.

So for the test setup, I would want to create a lot of Pnl objects with only certain concerned attributes with values, say,
date - last 5 days
book - from 1 to 10
etc

public class Pnl {

      private PnlKey pnlKey;

}



public class PnlKey {

    private String custodianAccount;



    private Integer bookId;



    private Integer pnlSpn;



    private Date date;



    private Integer bundleId;



}

@Bean
public EnhancedRandom getEnhancedRandomForPnl() {
 Randomizer<Date> dateRandomizer = () -> {
  int max = dates.length;
  Random random = new Random();
  return dates[random.nextInt(max)];
 };
 Randomizer<Integer> bookRandomizer = () -> {
  int min = 1;
  int max = 10;
  Random random = new Random();
  return min + random.nextInt((max - min) + 1);
 };
 Randomizer<Integer> bundleRandomizer = () -> {
  int min = 11;
  int max = 20;
  Random random = new Random();
  return min + random.nextInt((max - min) + 1);
 };
 Randomizer<String> custodianAccountRandomizer = () -> {
  Random random = new Random();
  return custodianAccounts[random.nextInt(custodianAccounts.length)];
 };
 EnhancedRandom enhancedRandom = EnhancedRandomBuilder.aNewEnhancedRandomBuilder()
   .randomize(Date.class, dateRandomizer)
   .randomize(new FieldDefinition<>("bookId", Integer.class, PnlKey.class), bookRandomizer)
   .randomize(new FieldDefinition<>("bundleId", Integer.class, PnlKey.class), bundleRandomizer)
   .randomize(new FieldDefinition<>("custodianAccount", String.class, PnlKey.class),
     custodianAccountRandomizer)
   .build();
 return enhancedRandom;
}
You can check how this is configured here

And how it is accessed/tested here

Friday, June 23, 2017

Overriding Spring Context Initializers

Consider the scenario where you need to override certain properties across the integration tests

User class with name and hobby

PropertySources :

NameHobbyPropertySource
public class NameHobbyPropertySource extends PropertySource<properties> {

 static Properties source = new Properties();
 
 public NameHobbyPropertySource(String name) {
  super(name, source);
  source.setProperty("name", "chinnu");
  source.setProperty("hobby", "cycling");
 }

 @Override
 public Object getProperty(String key) {
  return getSource().get(key);
 }
}

HobbyOnlyPropertySource
public class HobbyOnlyPropertySource extends PropertySource<properties> {

 static Properties source = new Properties();
 
 public HobbyOnlyPropertySource(String name) {
  super(name, source);
  source.setProperty("hobby", "running");
 }

 @Override
 public Object getProperty(String key) {
  return getSource().get(key);
 }
}

And this is your default context initializer for your application (that uses NameHobby property source)

public class MainApplicationContextInitializer implements ApplicationContextInitializer<configurableapplicationcontext> {

 public void initialize(ConfigurableApplicationContext applicationContext) {
  System.out.println("Main initializer called");
  NameHobbyPropertySource nameHobbyPropertySource = new NameHobbyPropertySource("name-hobby");
  applicationContext.getEnvironment().getPropertySources().addFirst(nameHobbyPropertySource);
 }

}
Say your BaseIntegrationTest is configured with initializer that has NameHobbyPropertySource

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = { MainApplicationContextInitializer.class
  }, locations = { "classpath:application-context.xml" })
public abstract class BaseApplicationTest {
 
}

but you want to override this for only one test class.
i.e. your special test case should run with overridden hobby from HobbyOnlyPropertySource. You can achieve this using inheritInitializers as follows,

public class SubSetApplicationContextInitializer implements
  ApplicationContextInitializer<configurableapplicationcontext> {

 public void initialize(ConfigurableApplicationContext applicationContext) {
  System.out.println("Subset initializer called");
  HobbyOnlyPropertySource hobbyOnlyPropertySource = new HobbyOnlyPropertySource(
    "hobby");
  applicationContext.getEnvironment().getPropertySources()
    .addFirst(hobbyOnlyPropertySource);
 }

}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = { SubSetApplicationContextInitializer.class }, inheritInitializers = true)
public class ApplicationTest extends BaseApplicationTest {

but this will not work because, By default the initializers of the derived class gets called and then the base class's initializers are called.

To override this behaviour, BOTH the initializer should implement Ordered interface and define an order.

Whichever one wants to run later should be given higher order. You can also try @Order annotation for the same.

 Lets say MainApplicationContextInitializer is from third party lib, and it doesn't implement or annotated with Order, then this wouldn't work. So have a wrapper over the third party initializer and annotate it with @Order.

@Order(0)
public class WrapperMainApplicationContextInitializer extends MainApplicationContextInitializer{

}
And so the BaseApplicationTest should now use this wrapper,
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = { WrapperMainApplicationContextInitializer.class
  }, locations = { "classpath:application-context.xml" })
public abstract class BaseApplicationTest {
 
}

and your subset application context initializer should also be ordered
public class SubSetApplicationContextInitializer implements
  ApplicationContextInitializer<configurableapplicationcontext>, Ordered {

 public void initialize(ConfigurableApplicationContext applicationContext) {
  System.out.println("Subset initializer called");
  HobbyOnlyPropertySource hobbyOnlyPropertySource = new HobbyOnlyPropertySource(
    "hobby");
  applicationContext.getEnvironment().getPropertySources()
    .addFirst(hobbyOnlyPropertySource);
 }

 public int getOrder() {
  return 1;
 }
}

Refer :

Monday, June 19, 2017

NullComparator

I will demonstrate the use of this comparator in the scenario below.

Let us consider some entity called Allocation

There are many types of allocations.
ALevelAllocation
BLevelAllocation
etc

All of them have month.

if month is null -> Global allocation
if month is not null -> Monthly allocation

So let us introduce an interface

public interface MonthLevelAllocationMarker {
    String getMonth();
}

class ALevelAllocation implements MonthLevelAllocationMarker{

class BLevelAllocation implements MonthLevelAllocationMarker{

This way when I need to write any custom comparator to sort the allocations, I need to write only one Comparator for type MonthLevelAllocationMarker

import org.apache.commons.collections.comparators.NullComparator;



public class MonthFirstAllocationSorter implements Comparator<MonthLevelAllocationMarker>, Serializable

{

    private static final long serialVersionUID = 1L;



    @Override

    public int compare(MonthLevelAllocationMarker a, MonthLevelAllocationMarker b)

    {

        boolean nullsAreHighForGlobalMonth = true;

        NullComparator nullComparator = new NullComparator(nullsAreHighForGlobalMonth);

        return nullComparator.compare(a.getMonth(), b.getMonth());

    }

}



I am using NullComparator to sort the nulls are high. Meaning Monthly allocations first and global allocation last.

Usage :

List<ALevelAllocation> allocations;

Collections.sort(allocations, new MonthFirstAllocationSorter());

Thursday, June 15, 2017

Generics - T extends Class & Interface

Say you have a Transaction object

public abstract class Transaction {
Long transactionId


And you have various transactions,

MoneyTransaction
RewardPointTransaction
CouponTransaction
etc

There are some of these transactions that are  Transferable and some are not

public interface Transferable {
    Long getDestinationAccount();
}

I need to write a common assertion while writing test case.

public void assertTransferableTransactions

takes in lists

expectedTransactions
actualTransactions

I would need transactionId to group the inputs, which is in type Transaction
And the methods to be in tested that are in Transferable

So I could have my assertion like

public static <T extends Transaction & Transferable> void assertTransferrableTransactions(
            List<T> expectedTransactions, List<T> expectedTransactions)

You can have just this method in a test util and avoid the code duplicate throughout all the Transaction tests that are transferable

Note that in
T extends A & B
class name should come first and interfaces follow.
i.e.
<T extends Transferable & Transaction> will give compilation error

Thursday, May 25, 2017

Functional Interfaces - Default and static methods

A cheat sheet is all that is needed to start using Java Lambdas. But here I will start with the design changes done in Java8 in order to accommodate Lambdas.

Most of the interfaces in the JDK have only method. (Comparator, Runnable, Callable, etc) These are Single Abstract Method interfaces. These SAM concepts are recreated in Java8 using Functional Interfaces. Since a lambda function can only provide implementation for one method, it is mandatory for your functional interface to have ONLY ONE interface

Functional Interface

Interface with only one abstract method.

Methods from the Object class do not count. i.e. The interface can also declare the abstract methods from the java.lang.Object class, but still the interface can be called as a Functional Interface. Example 

@FunctionalInterface

public interface SimpleFunctionalInterface {

  public void doWork();

  public boolean equals(Object o);

}


It can also have
- static methods 
- default methods

Note that the @FunctionalInterface is optional. It is just for convenience - the compiler can warn if it is not really a functional interface.

So what is the type of lambda expression? - Functional Interface
Is lambda expression an object? Well, it can be moved around like an object. An anonymous class is created with new. So I am explicitly asking JVM to create a new object (which is an overhead). but when I ask for a lamba, it is still recorded as an object in the JVM. But it is an object of a new kind in java8 - an object without an identity. I know this sounds complex. I will have a separate write-up on this. For now, the answer is no.

Default methods

In order to introduce lambda to Java 8, I need to add a forEach method to Iterable interface. Which will result in compilation error since all the classes that extends Iterable should provide an implementation for forEach. So I will be breaking the backward compatibility. 

Hence the default methods. A new Java8 concept to change the old interfaces without breaking the existing implementations. It provides flexibility to allow interface define implementation which will use as default in the situation where a concrete class fails to provide an implementation for that method. Meaning, they can be overridden. 

So what happens when the classes is implementing 2 interfaces with same default method signatures?

public interface InterfaceA {

    default void defaultMethod(){

        System.out.println("Interface A default method");

    }

}

public interface InterfaceB {

    default void defaultMethod(){

        System.out.println("Interface B default method");

    }

}

public class Impl implements InterfaceA, InterfaceB  {

}


So in these cases, to avoid compilation error, you have to provide your own implementation.
You can even choose to call either of the default methods like this:


public class Impl implements InterfaceA, InterfaceB {

    public void defaultMethod(){

        // existing code here..

        InterfaceA.super.defaultMethod();

    }

}

Summary:


When we extend an interface that contains a default method, we can perform following,
  • Override the default method similar to other methods we override in subclass..
  • Not override the default method and will inherit the default method.
  • Redeclare default method as abstract, which force subclass to override it.

Static Methods

The static methods in interfaces are good for providing utility methods.
Eg : isEquals in java.util.function.Predicate & identity in java.util.function.Function
We can’t define interface static method for Object class methods, we will get compiler error
as “This static method cannot hide the instance method from Object”. This is because
it’s not allowed in java, since Object is the base class for all the classes and we can’t have
one class level static method and another instance method with same signature.
These cannot be not overriden. if you think about it, it makes sense. Say I am providing a isNull
utility in my interface so that the implementations do it right, then I will prevent that
to be overridden
Now let us talk about the inheritance part a bit more. How about static methods in class?
public class SuperClass {
 public static void foo()
 {
  System.out.println("super class static");
 }
}

public class SubClass extends SuperClass{
 public static void foo()
 {
  System.out.println("sub class foo");
 }
}

public class App {
 public static void main(String[] args) {
  SuperClass.foo();
  SubClass.foo();
 }
}
This would have printed :
super class static sub class foo
What if there is no foo() in SubClass
public class SubClass extends SuperClass{
}
It still works :
super class static super class static
Now let us talk about static methods in interface
public interface SuperInterface {
 public static void foo()
 {
  System.out.println("super interface static");
 }
}
public interface SubInterface extends SuperInterface{
 public static void foo()
 {
  System.out.println("sub interface static");
 }
}

public class App {
 public static void main(String[] args) {
  SuperInterface.foo();
  SubInterface.foo();
 }
} 
Prints :
super interface static sub interface static
What if there is not foo in SubInterface? 
public interface SubInterface extends SuperInterface{
}

public class App {
 public static void main(String[] args) {
  SuperInterface.foo();
  SubInterface.foo(); -> compilation error }
}
Similarly, the following will work fine. Both class and interface can have static methods with same names, and neither overrides other
public class SomeClass implements SuperInterface{
 public static void foo()
 {
  SuperInterface.foo();
 }
}
public class App {
 public static void main(String[] args) {
  SomeClass.foo();
 }
}
but the moment you remove foo from SomeClass, it will result in compilation error
public class SomeClass implements SuperInterface{
}

public class App {
 public static void main(String[] args) {
  SomeClass.foo(); -> compilation error }
}
So why default can be inherited and static cannot? These are my favorite answer from stackoverflow.
1) A static method is a method that's associated with the class in which it's defined, rather than with any object created from that class. Every instance of the class shares the static methods of the class. Java 8 also lets static methods be defined in interfaces where they can assist default methods.
When you implement an interface that contains a static method, the static method is still part of the interface and not part of the implementing class. For this reason, you cannot prefix the method with the class name. Instead, you must prefix the method with the interface name
2) Static methods in interfaces could create a diamond of death if they were being inherited. So, calling a static method from the appropriate interface is good enough compared to the risk of calling it from a concrete class that may implement multiple interfaces that contain static methods of the same name.
Why are static methods any different?
Static methods are just functions unrelated to the objects. Instead of placing them in utility abstract classes (like calling Collections.sort() ) we move those functions (static methods) to their appropriate interfaces. They could be bound to the inherited objects like the default methods do, but that is not their job. Static methods provide functionality which is unrelated to the instances of the class.
Example:
interface Floatable {

    default void float() {
        // implementation
    }

    static boolean checkIfItCanFloat(Object fl) {
         // some physics here
    } 
}

class Duck implements Floatable { }
So, the point is that a Duck may float but the function that checks if an Object really floats is not something that a Duck can do. It is an irrelevant functionallity that we could pass to our Floatable interface instead of having it sit inside some utility class.

References :

Thursday, May 18, 2017

Parameterized Junit test

I have used the Parameterized Junit test in places where you need to test a method with huge combinations of input. Imagine a truth table logic in place.
Form the truth table -> let's take 2 inputs for simplicity sake.
A
B
Expected
1
1
1
1
0
1
0
1
1
0
0
0

Say if the method is,
Method(param1, param2)
Now if I have to go with the conventional junit test cases, I would have to name my methods like,
  • testMethodForParam1TrueParam2False()
  • testMethodForParam1TrueParam2True()
  • testMethodForParam1FalseParam2True()
  • testMethodForParam1FalseParam2False()
Sure it looks readable now. But consider the same for a 3 X 3 matrix. It becomes ugly.
Wouldn't it better to actually have this truth table in the start of the test case and feed it to just one test?
This is exactly what Parameterized Junit solves.
There are various blogs and sources to refer the syntax of such test.
But when you want to use it in an integration test, you need to keep the following in mind.
  1. As long as your data is static, you have nothing to worry about. Say, your service which contains the method, is initialized in @BeforeClass and in your @Parameterized.Parameters the data you feed is coming from a static method in that service. Then you will get NPE. Because @Parameters is called before @BeforeClass. To tackle this, have your initialization in a simple static block. But then, you need to make the test class final. @BeforeClass will apply to all the inherited classes, static block will not.
    package com.foo;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertNotNull;
    
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Date;
    import java.util.List;
    import java.util.Optional;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    
    
    @RunWith(Parameterized.class)
    public final class ServiceTest {
     private static Service service;
    
     private Integer param1;
     private Integer param2;
     private Integer expectedResult;
     private String caseName;
    
     static {
     setUpClass();
     }
    
     public static void setUpClass() {
     service = (Service) CustomContextLoader.getBean("service");
     }
    
     public ServiceTest(String caseName, Integer param1, Integer param2, Integer expectedResult) {
     this.caseName = caseName;
     this.param1 = param1;
     this.param2 = param2;
     this.expectedResult = expectedResult;
     }
    
     @Parameterized.Parameters
     public static Iterable<Object[]> testData()
     {
     return Arrays.asList(new Object[][]{
     { "case 1 : 1 1 = 1", 1, 1, 1},
     { "case 2 : 1 0 = 1", 1, 0, 1},
     { "case 3 : 0 1 = 1", 0, 1, 1},
     { "case 4 : 0 0 = 0", 0, 0, 0},
     });
    
     }
    
     @Before
     public void setup() {
     System.out.println("@Before");
     }
    
     @Test
     public void testMethod() {
     Integer result = service.orMethod(this.param1, this.param2);
     assertEquals(this.caseName+" failed", this.expectedResult, result);
     }
    
    }
    Remember the order of execution
    Static block
    @Parameter
    @BeforeClass
    @Before
    @Test
    For my case, I had to bootstrap some data (think of inserting some rule and referencing that throughout your test case using an ID. In such case I need to insert the rule and get the ID before I can setup the data) before I can set test data. Hence it was important for the service to be initialized before it hit the @Parameters method. I could not use @BeforeClass because it gets executed after @Parameters. Hence I had to resort to static method.
  2. Add a description for each test data you setup in the @Parameters. and add this to the assertion string. This will help identify which dataset is failing. Because, since this is parameterized test, the test results would be printed something like this:
    com.foo.ServiceTest > testMethod[0] PASSED
    com.foo.ServiceTest > testMethod[1] PASSED
    com.foo.ServiceTest > testMethod[2] FAILED
    java.lang.AssertionError
    com.foo.ServiceTest > testMethod[3] PASSED
    Now if you have setup a caseName with the testData, you will spend less time debugging the issue.
    com.foo.ServiceTest > testMethod[0] PASSED
    com.foo.ServiceTest > testMethod[1] PASSED
    com.foo.ServiceTest > testMethod[2] FAILED
    java.lang.AssertionError : case 3 : 0 1 = 1 failed
    com.foo.ServiceTest > testMethod[3] PASSED
    Also note that the parameterized junit test runs like there are separate @Test methods for all of those data sets. Means it will continue running all the tests even if one fails. It is not fail-fast.

KeySet And UnsupportedOperationException

package com.foo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Test;

public class SomeTest {
 @Test
 public void test() {
 Map<String, Set<String>> movieToActorsName = new HashMap<>();
 Set<String> actors = new HashSet<>();
 actors.add("Dan");
 actors.add("Emma");
 movieToActorsName.put("HP", actors);
 Map<String, Set<String>> someMap = new HashMap<>();
 someMap.put("Movies", new HashSet<>(movieToActorsName.keySet()));
 someMap.values().stream().forEach(s -> {
 s.add("dummy");
 });
 someMap = new HashMap<>();
 someMap.put("Movies", movieToActorsName.keySet());
 someMap.values().stream().forEach(s -> {
 s.add("dummy"); // UnsupporrtedOperationException. Because keySet() is immutable.
 });
 }
}
Keyset is basically just a view of the keys in the map. So If you call remove() on the keyset, it will actually remove the entry for that key in the map.
I found this common where people directly take keySet of a map into a placeholder, which will be modified in the later part of the code. The following is wrong.
placeHolderMap.put(id, referenceMap.keySet());
And this is right.
placeHolderMap.put(id, new HashSet<>(referenceMap.keySet()));
or
placeHolderMap.put(id, referenceMap.keySet().stream().collect(Collectors.toSet()));