I have method that is called by another service and it just change one of the field for some rows in database. Method looks like this:
void errorOrders() {
List<Orders> orders = OrderDAO.getErrorOrders(); //select only fields with status 'error'
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
//some logging etc.
}
Is there any way to unit test this method? Can I inject myself inside this method and check if orders status was changed?
Cheers!
I would recommend you refactor your class to make your code testable. Ideally you would inject the dependency that represents the OrderDAO:
class ErrorChecker {
private final OrderDAO orderDAO;
public ErrorChecker(OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public void errorOrders() {
List<Orders> orders = orderDAO.getErrorOrders();
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
}
}
Then your test code would look like:
#Test
void testErrorOrders() {
Order order1 = mock(Order.class);
Order order2 = mock(Order.class);
OrderDAO orderDAO = mock(OrderDAO.class);
when(orderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
verify(order1).setState(OrderStatus.NEW);
verify(order2).setState(OrderStatus.NEW);
}
There are ways to mock static methods but I would recommend refactoring to inject the dependencies as it has many other benefits beside testability.
If you need to leave the method as static then you can still mock it (in v3.4+ of Mockito):
#Test
void testErrorOrders() {
try (MockedStatic mocked = mockStatic(OrderDAO.class)) {
mocked.when(OrderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
mocked.verify(order1).setState(OrderStatus.NEW);
}
}
#ismail and #khelwood already provided good answers.
If you mock the Object, you can control/see what happens to it
If you change an Object, where you can access the state via public methods, use those
If you change an Object whose state you cannot access with normal code, use Java Reflections to look at member variables.
If you set up Objects, that pass their data to streams and other output, you can put some additional streams etc in between. Use inheritance and reflection if necessary
Simple example of using Reflection on a shielded class:
package stackoverflow.simplefieldaccess;
public class ShieldedClass {
private int mStatus;
public ShieldedClass() {
mStatus = 666;
}
public void setStatus(final int pStatus) {
mStatus = pStatus; // usually with ints be careful and do checks here, but for the sake of simplicity we leave that out
}
#Override public String toString() {
return getClass().getSimpleName() + "[status:" + mStatus + "]";
}
}
Code to access it via reflection in a few ways:
package stackoverflow.simplefieldaccess;
import java.lang.reflect.Field;
import jc.lib.lang.reflect.JcFieldAccess;
public class SimpleFieldAccess {
public static void main(final String[] args) throws NoSuchFieldException, SecurityException {
final ShieldedClass so = new ShieldedClass();
System.out.println("Object.status before change: " + so);
so.setStatus(667);
System.out.println("Object.status after change: " + so);
System.out.println();
System.out.println("Accessing Object.status via Reflection...");
final Class<? extends ShieldedClass> cls = so.getClass();
final Field fieldToChance = cls.getDeclaredField("mStatus");
{
System.out.println("\nBad read access");
try { // will result in java.lang.IllegalAccessException
System.out.println("\tReading Object.status fiels via Reflection: " + fieldToChance.getInt(so));
throw new IllegalStateException("UNEXOECTED ERROR!");
} catch (final java.lang.IllegalAccessException e) {
System.out.println("\tAs expected: IllegalAccessException");
}
}
{
System.out.println("\nBad write access");
try { // will result in java.lang.IllegalAccessException
fieldToChance.set(so, Integer.valueOf(1337));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
System.out.println("\tAs expected: IllegalAccessException");
}
}
{
System.out.println("\nGood manual read and write access");
final boolean isFieldOriginallyAccessible = fieldToChance.isAccessible();
try { // will result in java.lang.IllegalAccessException
if (!isFieldOriginallyAccessible) fieldToChance.setAccessible(true);
System.out.println("\tReading Object.status field via Reflection: " + fieldToChance.getInt(so));
fieldToChance.set(so, Integer.valueOf(4321));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
e.printStackTrace();
} finally {
if (!isFieldOriginallyAccessible) fieldToChance.setAccessible(false);
}
}
{
System.out.println("\nGood automated read and write access");
try (JcFieldAccess fa = new JcFieldAccess(fieldToChance)) { // will result in java.lang.IllegalAccessException
System.out.println("\tReading Object.status field via Reflection: " + fieldToChance.getInt(so));
fieldToChance.set(so, Integer.valueOf(123));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
For reflections, when I want to access fields, I use my homebrew class that makes it easier to get access to the field and afterwards restore it to normal (last example above uses this):
package jc.lib.lang.reflect;
import java.io.Closeable;
import java.lang.reflect.AccessibleObject;
public class JcFieldAccess implements Closeable {
private final AccessibleObject mField;
private final boolean mIsAccessible;
public JcFieldAccess(final AccessibleObject pField) {
mField = pField;
mIsAccessible = mField.isAccessible();
if (!mIsAccessible) mField.setAccessible(true);
}
#Override public void close() {
if (mIsAccessible) return;
if (mField != null) mField.setAccessible(false);
}
}
The trick with this util class is that when used in a try-resource block, its close() method will get called automatically, whether the block fails or not. It's the same as having the close() or in this case setAccessible(false) call in the finally block, with some extra checks.
Let the class be:
class HandleErrorOrders {
private OrderDAO orderDAO;
HandleErrorOrders(final OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public void errorOrders() {
List<Orders> orders = OrderDAO.getErrorOrders(); //select only fields with status 'error'
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
//some logging etc.
}
}
You need to use assert methods to check end state.
To test, write something like:
class HandleErrorOrdersTest {
#Mock
private OrderDAO orderDAO;
#InjectMocks
private HandleErrorOrders handleErrorOrders;
#Test
void testErrorOrders() {
Order order1 = mock(Order.class);
Order order2 = mock(Order.class);
when(orderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
//asset checks
Assert.assertEquals(OrderStatus.NEW, order1.getStatus());
Assert.assertEquals(OrderStatus.NEW, order2.getStatus());
//verification checks
Mockito.verify(orderDAO).getErrorOrders();
}
}
Related
I have the following implementation:
private SomeWritter someWritter(String someArgument) {
SomeWritter.Builder builder = SomeWritter.builder(someArguments);
builder = builder.addColumn("colName1", TargetClass::getArg1)
builder = builder.addColumn("colName2", TargetClass::getArg2)
return builder.build();
}
private Builder<T> addColumn(String colName, ToDoubleFunction<T> getter){
//implementation goes here
}
my issue is that I need to iterate over the addColumns call, something among these lines:
private void SomeWritter(String someArgument) {
SomeWritter.Builder builder = SomeWritter.builder(someArguments);
for (Field field : getFilteredFieldsFromClass(TargetClass.class)) {
builder = builder.addColumn(field.getName(), [SOMEHOW GET THE REF TO GETTER HERE])
}
return builder.build();
}
in order to get the refference to the getter, I tryed to do
TargetClass.class.getMethod("getArg1", ...);
this works, but I have a Method, not a ToDoubleFunction.
I need to somehow get that ToDoDoubleFunction, programatically, I want to do the same that the TargetClass:: does, dinamically, not harcoded. any ideas ?
import java.lang.reflect.Field;
public class Main {
static class Example{
double arg1;
int arg2;
}
interface Foo<T>{
double toDouble(T example);
}
public static void addColumn(Foo<Example> foo){
//do nothing
}
public static void main(String[] args) {
final var example = new Example();
for(Field field: Example.class.getDeclaredFields()){
addColumn(example1 -> {
try {
return (double) field.get(example1);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
}
}
That code iterates over all fields of the Example class and uses the reflection inside a lambda.
Side Note. Intellij can replace method references with lambda when you click alt+enter when cursor is on them (Windows).
I have Utils class with method which throws exception when given data are incorrect.
I have also Service which uses this method, but the data are always generated in way that they will be correct during call. Data are generated by another utils class.
I understand that I should throw this exception from Utils class - but I can't throw it from Service - so I have to catch it.
How can I test this, simulate this exception?
All actions on this data are in private methods.
I want to avoid PowerMock, because I heard that it's a sign of bad design.
So the question is, how to implement this in good design?
From your description it looks like this:
class Service {
public void someMethod() {
Data data = AnotherUtils.getData();
try {
Utils.method(data); // exception never thrown
} catch(Exception e) {
// how to test this branch?
}
}
}
The goal would be something like this:
interface DataProvider {
Data getData();
}
interface DataConsumer {
void method(Data data);
}
class Service {
private final DataProvider dataProvider;
private final DataConsumer dataConsumer;
public Service(DataProvider dataProvider, DataConsumer dataConsumer) {...}
public void someMethod() {
Data d = dataProvider.getData();
try {
dataConsumer.method(data);
} catch(Exception e) {
}
}
}
This technique is called dependency injection.
Then, when testing, you can simply provide a mock implementation for this DataProvider interface that does return faulty data:
#Test(expected=Exception.class)
public void myTest() {
DataProvider badDataProvider = () -> new BadData(); // Returns faulty data
Service service = new Service(badDataProvider, Utils.getConsumer());
service.someMethod(); // boom!
}
For the non-testing code, you could simply wrap the utils classes you already have in these interfaces:
class AnotherUtils {
public static Data getData() {...}
public static DataProvider getProvider() {
return AnotherUtils::getData;
}
}
...
Service service = new Service(AnotherUtils.getProvider(), Utils.getConsumer());
Here is an approach where you want to introduce Dependency Injection, but for whatever reason you don't want to change legacy code.
Say you have some static utility method like so:
class Utils{
public static Something aMethod(SomethingElse input) throws AnException{
if(input.isValid())
return input.toSomething();
throw new AnException("yadda yadda");
}
}
And you have a class that uses that utility method. You can still inject it with a FunctionalInterface.
#FunctionalInterface
interface FunctionThrowsAnException<K,V> {
V apply(K input) throws AnException;
}
class Service {
private final FunctionThrowsAnException<SomethingElse,Something> func;
Service(FunctionThrowsAnException<SomethingElse,Something> func){
this.func = func;
}
Something aMethod(SomethingElse input){
try{
return func.apply(input);
}catch(AnException ex){
LOGGER.error(ex);
}
}
}
Then use it like this:
new Service(Utils::aMethod).aMethod(input);
To test it:
new Service(x -> { throw new AnException("HA HA"); }).aMethod(input);
I want use a Powermock to test a private method (one) but this private method relies on another private method (two).
So I have to mock the other private method. But while I am debugging it, it turns out that the private method one is not calling the mocked private method (two) and if I run instead of debugging it throws out exception:
1matchers expected, 2 recorded.
private int getCurrentLocaleID(WebIServerSession currentSession, String preferenceName) {
String prefLocaleID = getUserPreference(currentSession, preferenceName);
int lcid;
if (HTTPHelper.isDefaultLocale(prefLocaleID)) {
prefLocaleID = _appContext.getBrowserHeaderLocaleId();
}
try {
lcid = Integer.parseInt(prefLocaleID);
} catch (NumberFormatException nfe) {
lcid = DEFAULT_LCID; // default behavior from old session manager
}
return lcid;
}
#Test
public void getCurrentLocaleID() throws Exception {
PowerMockito.mockStatic(HTTPHelper.class);
WebAppSessionManagerImpl webAppSessionMangerImpl2 = PowerMockito.spy(new WebAppSessionManagerImpl(appConext));
given(HTTPHelper.isDefaultLocale("1")).willReturn(true);
given(HTTPHelper.isDefaultLocale("0")).willReturn(false);
given(appConext.getBrowserHeaderLocaleId()).willReturn("1");
PowerMockito.doReturn("1").when(webAppSessionMangerImpl2, "getUserPreference", anyObject(), anyString());
int result = Whitebox.invokeMethod(webAppSessionMangerImpl2, "getCurrentLocaleID", webIserverSession, "test");
assertEquals(result, 1);
}
Dont test private methods. If you have to, that means that your class is doing too much than it supposed to and it does not comply with the Single Responsibility Principle.
This is a chance for some refactoring and isolation of logic in specialized class like something follwing:
public class SpecializedClass{
private Context context;
public SpecializedClass(Context context){
this.context = context;
}
public int getCurrentLocaleID(WebIServerSession currentSession, String preferenceName) {
String prefLocaleID = getUserPreference(currentSession, preferenceName);
int lcid;
if (HTTPHelper.isDefaultLocale(prefLocaleID)) {
prefLocaleID = _appContext.getBrowserHeaderLocaleId();
}
try {
lcid = Integer.parseInt(prefLocaleID);
} catch (NumberFormatException nfe) {
lcid = DEFAULT_LCID; // default behavior from old session manager
}
return lcid;
}
String getUserPreference(Session session, String preferenceName){..}
}
Now haiving the method public and the getUserPreference marked as package level, the test would look something like:
#Test
public void getCurrentLocaleID() throws Exception {
PowerMockito.mockStatic(HTTPHelper.class);
SpecializedClass specializedClassSpy = Mockito.spy(new SpecializedClass(appConext));
given(HTTPHelper.isDefaultLocale("1")).willReturn(true);
given(HTTPHelper.isDefaultLocale("0")).willReturn(false);
given(appConext.getBrowserHeaderLocaleId()).willReturn("1");
Mockito.doReturn("1").when(specializedClassSpy)
.getUserPreference(webIserverSession, "test");
int result = specializedClassSpy.getCurrentLocaleID(webIserverSession, "test");
assertEquals(result, 1);
}
I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}
I'm having an issue with my configuration management class, it is not getting reloaded.
Let me show you part of my code:
public class ConfigurationManager extends XMLConfiguration
{
private static final Logger log = LoggerFactory.getLogger(ConfigurationManager.class);
private static final long serialVersionUID = 1L;
public static final String CONFIG_FILE_PATH = "/config.xml";
private static volatile ConfigurationManager instance = null;
private static Object lock = new Object();
// Instance management methods
public static ConfigurationManager getInstance()
{
return getInstance(CONFIG_FILE_PATH);
}
public static ConfigurationManager getInstance(String cfg)
{
if(instance == null)
{
synchronized(lock)
{
if(instance == null)
{
try
{
instance = new ConfigurationManager(cfg);
instance.dumpConfigurationToLog();
}
catch(Exception e)
{
log.error("Error calling getInstance. Method params", e);
}
}
}
}
return instance;
}
private Object loadedCfg;
private int reloadInterval;
private void dumpConfigurationToLog()
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
this.save(bos);
bos.flush();
}
catch(Exception e)
{
log.error("Error calling dumpConfigurationToLog. Method params", e);
}
}
#Override
public void configurationChanged(ConfigurationEvent event)
{
log.info("Enter Method configurationChanged params: {}", event);
if(event.isBeforeUpdate() == false)
{
makeUpdates();
log.info("Configuration file: {} has changed and reloaded...", loadedCfg);
dumpConfigurationToLog();
}
log.info("Return Method configurationChanged");
}
private void updateReloadInterval()
{
int newReloadInterval = getInt("global.reloadInterval") * 1000;
if(reloadInterval != newReloadInterval)
{
reloadInterval = newReloadInterval;
if(getReloadInterval() > 0)
{
FileChangedReloadingStrategy reloadStrategy = new FileChangedReloadingStrategy();
reloadStrategy.setRefreshDelay(getReloadInterval());
this.setReloadingStrategy(reloadStrategy);
}
else
if(getReloadInterval() == 0)
{
this.setReloadingStrategy(new InvariantReloadingStrategy());
}
else
{
log.error("Invalid reload interval for ConfigurationManager: {}", getReloadInterval());
}
}
}
private ConfigurationManager(String cfgFile) throws Exception, ConfigurationException
{
super();
loadedCfg = cfgFile;
if(System.class.getResource(cfgFile) != null)
this.setURL(System.class.getResource(cfgFile));
else
this.setURL(getClass().getResource(cfgFile));
this.load();
makeUpdates();
this.addConfigurationListener(this);
this.setThrowExceptionOnMissing(true);
}
private void makeUpdates()
{
updateReloadInterval();
}
public int getReloadInterval()
{
return reloadInterval;
}
}
Now that code works perfectly fine, I can read the configuration file, and work with it with no major problems, the issue is that it never gets reloaded on configuration changes. I've tried setting breakpoints and so, but it never gets into configurationChanged method.
Does anybody see something wrong here?
Well, after testing and analyzing, I've got to this conclusion, in order to have configurationChanged called, I need to make an explicit call to get values from configuration.
And that is something I was not doing.
The thing got fixed when I did that.
You're calling makeUpdates() after setting your ConfigurationListener.
Additionally, calling load() is no guarantee that an Event will get fired.
Lastly, is there anything actually calling addProperty(), etc for this extended class?
Only a small side issue: resource bundles are cached, you can call clearCache, unfortunately not per bundle but per class loader.