How do I call populateMapWithFormattedDates method in JUnit and how to write JUnit populateMapWithFormattedDates for this method. I dont know how to write JUnit for nested methods so kindly help.
protected Map<String, String> populateDispatch(final RequestDispatchData requestDispatchData)
{
final Map<String, String> map = getDispatchFieldMapper().populateMapper(requestDispatchData);
populateMapWithFormattedDates(requestDispatchData, map);
}
private void populateMapWithFormattedDates(final RequestDispatchData requestDispatchData, final Map<String, String> map)
{
String dateFormatted = map.get("ticket_date");
Date date = null;
try
{
date = new SimpleDateFormat("MM/dd/yy").parse(dateFormatted);
}
catch (ParseException parseException)
{
customLogger.logMessage(diagnosticMethodSignature, DiagnosticType.EXCEPTION,
"Exception in parsing start date of ticket " + parseException);
}
map.put("startDateDDMMYY", DateEnum.DDMMYY.getFormattor().format(date));
map.put("startDateDDMMMYY", DateEnum.DDMMMYY.getFormattor().format(date));
map.put("startDateDMY", DateEnum.DMY.getFormattor().format(date));
map.put("startDateYYMMDD", DateEnum.YYMMDD.getFormattor().format(date));
}
Simple: you don't test private methods directly.
Instead, you focus on the "public contract" of those methods that get invoked "from the outside". In your case, that would be:
Map<String, String> populateDispatch(...
Thus you want write tests like:
#Test
public void populateDispatchForValidDate() {
RequestDispatchData request = ...
Map<String, String> actualOutput = underTest.populateDispatch(request);
assertThat(actualOutput.size(), is(5));
}
The above is just meant as an example. What it does:
create a "request" object. This could be a mock; or a real object - depends on what exactly your various methods are doing with this object. And how easy it is to create a "real" RequestDispatchData object with "test data"
it invokes that method under test
it asserts one/several properties of the result coming back
Looking at your production code, that code is doing way too many things within that single method. You might want to read about "clean code" and improve that code. That probably lead to the creation of some helper classes which would be easier to test then.
There is nothing such as a nested method in Java. It's a nested function call is what it is. Plus, yea, you cannot call the private functions of a class through its object so testing them individually by calling them is not possible.
You can although have a public or protected function doing the call somewhat like a getter.
I believe your code is some what like,
protected Map<String, String> populateDispatch(final RequestDispatchData requestDispatchData)
{
final Map<String, String> map = getDispatchFieldMapper().populateMapper(requestDispatchData);
return populateMapWithFormattedDates(requestDispatchData, map);
}
note that you have missed the return statement, and update the map on certain condition from ,
private void populateMapWithFormattedDates(final RequestDispatchData requestDispatchData, final Map<String, String> map)
{
// Map manipulation here
}
So if you have minimum dependency on the getDispatchFieldMapper().populateMapper(), then you can directly invoke populateDispatch() from your test code, else you may have to find a way to inject a custom implementation of DispatchFieldMapper to prepare the map for testing your target method.
Injection of DispatchFieldMapper can be via overriding the getDispatchFieldMapper() or use a setDispatchFieldMapper() on your class.
While preparing your custom DispatchFieldMapper, make sure the populateMapper() returns a map with all data required for your testing.
It is not good idea to call non accessible method while testing directly form the test class.
Second thing : Non accessible method is always called form some accessible method or scope otherwise that code is dead code just remove that.
Because method is privet, so if it is in use then it called somewhere from code of current class. in your code it called form populateDispatch, so actual way to write test case for populateMapWithFormattedDates method is cover all the scenarios for populateDispatch method and populateDispatch is also used form sub class of the current class call it form there.
But you can call private method in junit like:
Deencapsulation.invoke(<object of class in called method is exist>, "populateMapWithFormattedDates", <object of RequestDispatchData class>, <object of Map<String, String> class>);
Again it is a way to call private method but you should not use this...
You should decouple the populateMapWithFormattedDates method like this:
// I created an utility class but it's a suggestion.
// I'm using an util class because you don't use requestDispatchData for
// anything. But if you do, maybe it's a good idea to implement this code
// on RequestDispatchData class
class DispatchMapUtils {
// Note that I took of the requestDispatchData
public static Map<String, String> populateMapWithFormattedDates(final Map<String, String> map) throws ParseException {
// Your code without try-catch.
// Throw the exception to the caller of this method
// and try-catch there to use the customLogger
}
}
With this code, your test would be something like this:
#Test
public void shouldFormatTicketDateInVariousFormat() {
Map<String, String> map;
// Instantiate and put some initial datas
map = new ...
map.put('ticket_date') = ..
// Call the method!
DispatchMapUtils.populateMapWithFormattedDates(map);
// Do the assertions!
Assert.assertTrue(map.get("startDateDDMMYY").equals(...));
}
#Test
public void shouldThrowExceptionWhenTicketDateIsInvalid() {
// More testing code
}
Related
I want to initialize a hashmap inside an nested interface. I have tried doing smtng like
interface constants{
.........
.........
interface anotherInterface{
........
........
Map<String, HttpMethod> API_METHOD = new HashMap<String,HttpMethod>();
API_METHOD.put(POST, HttpMethod.POST);
}
}
but this is givin error "Cannot resolve symbol 'put'".
can someone please tell me the reason for this and some other way to initialize the map.
Note: I don't want to initialize my map like and i am using java 8
new HashMap<String, HttpMethod>() {
{
put(POST, HttpMethod.POST);
}
};
Any 'field' in an interface immediately becomes a public static final one, therefore, making a mutable field is an incredibly bad idea - that's making global state, the thing just about every style guide out there lists as number one on the list of 'bad ideas'.
But, you're trying to 'initialize it', so I think your intent is that this map is itself 'constant' (it has a bunch of key/value mappings and can no longer be changed).
You have a few options.
You don't have many k/v pairs
Map<String, HttpMethod> API_METHOD = Map.of(
"POST", HttpMethod.POST,
"GET", HttpMethod.GET);
You have a lot of k/v pairs
Use the guava (a.k.a. google collections) library.
Then you can do:
Map<String, HttpMethod> API_METHOD = ImmutableMap.<String, HttpMethod>builder()
.put("POST", HttpMethod.POST)
.put("GET", HttpMethod.GET)
.build();
You have a lot and do not want to use guava
Now it gets a little mad, especially without java 11. You can write a static method in a class (which can be private if you want), and then call that static method from your interface:
public interface MyInterface {
Map<String, HttpMethod> httpMethods = MyInterfaceUtil.makeHttpMethodMap();
}
class MyInterfaceUtil {
static Map<String, HttpMethod> makeHttpMethodMap() {
Map<String, HttpMethod> map = new HashMap<>();
map.put("POST", HttpMethod.POST);
return Collections.unmodifiableMap(map);
}
}
Note:
That util class can be in the same file, but you should not make it public.
Collections.unmodifiableMap is very important.
Hello I am fairly new to unit testing with Junit as well as Mockito. I think I have a fairly reasonable understanding of the principles but I can't seem to find any explanations of what I am specifically trying to test online.
I want to test a method, that calls several other methods (void and non-void), which also instantiates objects in the method body. I unfortunately cannot share the code as it is not mine, but here is a general format:
class classToTest {
private final field_1;
public void methodToTest( string id, List object_1, List object_2) {
try {
Map<SomeObject_1, SomeObject_2> sampleMap = new HashMap<>();
method_1(object_1, object_2); //void function modifies object_2
field_1.method_2(id, object_2);
Map<SomObeject_1, List<object>> groupedList = groupList(object_2)
//Then some stuff is added to the sampleMap
}
//catch would be here
}
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call. I wish I could change the code but I have been asked to keep it the same and to test in this manner with Mockito and Junit.
I know I need to Mock an object of the class to Test as well as its parameter:
private classToTest classToTestObject;
#Mock private field_1 f1;
#Before
public void setup() {
MockitoAnnotations.init.Mocks(this);
classToTestObject = mock(classToTest.class, CALLS_REAL_METHODS);
}
but I don't know where to start my actual test, as in how I can essentially just execute that one method call and ignore all the rest. I can't just not ignore the other objects and method calls either as the main method will throw exceptions if they are not handled correctly.
Any help and guidance is much appreciated, sorry that I could not share the code. Thank You!
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call.
Per your comment, and the note in your code:
method_1(object_1, object_2); //void function modifies object_2
You would set up a test that allows you to verify the expected final state of object_2. You would do this with a real instance of the class, not a mock.
#Test
public void method1Test() {
// Assemble - your preconditions
ClassToTest subject = new ClassToTest();
List<SomeType> object_1 = new ArrayList();
List<SomeOtherType> object_2 = new ArrayList();
// Populate object_1 and object_2 with data to use as input
// that won't throw exceptions. Call any methods on subject that put
// it in the desired state
// Act - call the method that calls the method under test
subject.methodToTest("some id that makes the method run correctly", object_1, object_2);
// Assert - one or more assertions against the expected final state of object_2
assertThat(object_2).matchesYourExpectations();
}
My Java REST service accepts some query parameters and values. I want to apply some transformation functions to these parameter and values before I pass these to another service through REST API. I want to know the best way to transform these parameters in such a way that it can be as clean as possible for extension.
Here was my attempt to do this before and hope it also illustrates this better -
I created an enum which takes a Function like this:
public enum MyQueryParam {
ID("id", new MyCryptoFunction()),
PRICE("price", new CurrencyConvertFunction()),
...
private String mappedParam;
private Function<String, String> mappingFunction;
MyQueryParam(String mappedParam, Function<String, String> mappingFunction) {
this.mappedParam = mappedParam;
this.mappingFunction = mappingFunction;
}
public String getMappedParam() {
return mappedParam;
}
}
static class MyCryptoFunction implements Function<String, String> {
public String apply(String msg) {
// do the hash function
}
}
// .. somewhere in the code where I get the query params and values as a map
paramMap.forEach((param, value) -> uriBuilder.addParameter(param.getMappedParam(), param.mappingFunction.apply(value)));
So my id parameter gets encrypted and my price parameter gets currency converted statically.
Problem now comes when, these transformations need to be done based on some additional context that comes with each parameter. For example, I want to pass the locale from the request to the CurrencyConvertFunction. And I want to pass a secret key to the CryptoFunction. I cannot do new CurrencyConvertFunction(locale) in the enum given its static. What is a clean and elegant way to map my query parameters to applying some transformations and make it extensible?
(For example, I can check the value of the param as I am iterating through each parameter and do the validation there, but that feels like making the code un-maintainable).
You can update MyCryptoFunction to
static class MyCryptoFunction implements Function<Pair<String, String>, String> {
public String apply(Pair<String, String> param) {
// do the hash function
}
}
and also change the type of mappingFunction in MyQueryParam accordingly.
Then you can call the mappingFunction as
param.mappingFunction.apply(Pair.of(value,"additionalParam")).
You can also replace Pair with your custom class if you like.
We are working with mvc design pattern, where all the data is stored under map.
I want to iterate over all the classes in the system and for each to check what the method is putting on the map and what does the method get from the map.
For example for the next code:
private void myFunc()
{
Object obj = model.get("mykey");
Object obj2 = model.get("mykey2");
.....
model.put("mykey3", "aaa");
}
I want to know that in this function we have 2 gets: mykey and mykey2 and 1 put: mykey3
How can I do it with the code.
Thanks.
You tagged this with "reflection", but that will not work. Reflection only allows you to inspect "signatures". You can use it to identify the methods of a class, and the arguments of the methods.
It absolutely doesn't help you to identify what each method is doing.
In order to find out about that, you would need to either parse the java source code side, or byte code classes. As in: write code that reads that content, and understands "enough" of it to find such places. Which is a very challenging effort. And of course: it is very easy to bypass all such "scanner" code, by doing things such as:
List<String> keysToUpdate = Arrays.asList("key1", "key2");
for (String key : keysToUpdate) {
... does something about each key
Bang. How would you ever write code that reliable finds the keys for that?
When you found that code, now imagine that the list isn't instantiated there, but far away, and past as argument? When you figured how to solve that, now consider code that uses reflection to acquire the model object, and calls method on that. See? For any "scanner" that you write down, there will be ways to make that fail.
Thus the real answer is that you are already going down the wrong rabbit hole:
You should never have written:
Object obj = model.get("mykey");
but something like
Object obj = model.get(SOME_CONSTANT_FOR_KEY_X);
Meaning: there is no good way to control such stuff. The best you can do is to make sure that all keys are constants, coming from a central place. Because then you can at least go in, and for each key in that list of constants, you can have your IDE tell you about their usage.
NOTES
I assumed that your situation is complicated enough that simple or advanced text search in codebase doesn't help you.
This is a hack not a generic solution, designed only for testing and diagnosis purposes.
To use this hack, you must be able to change your code and replace the actual model with the proxy instance while you're testing/diagnosing. If you can't do this, then you have to use an even more advanced hack, i.e. byte-code engineering with BCEL, ASM, etc.
Dynamic proxies have drawbacks on code performance, therefore not an ideal choice for production mode.
Using map for storing model is not a good idea. Instead a well-defined type system, i.e. Java classes, should be used.
A general design pattern for a problem like this is proxy. An intermediate object between your actual model and the caller that can intercept the calls, collect statistics, or even interfere with the original call. The proxied model ultimately sends everything to the actual model.
An obvious proxy is to simply wrap the actual model into another map, e.g.
public class MapProxy<K, V> implements Map<K, V> {
public MapProxy(final Map<K, V> actual) {
}
// implement ALL methods and redirect them to the actual model
}
Now, reflection doesn't help you with this directly, but can help with implementing a proxy faster using dynamic proxies (Dynamic Proxy Classes), e.g.
#SuppressWarnings("unchecked")
private Map<String, Object> proxy(final Map<String, Object> model) {
final InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Collect usage stats or intervene
return method.invoke(model, args);
}
};
return (Map<String, Object>) Proxy.newProxyInstance(Map.class.getClassLoader(),
new Class<?>[] { Map.class }, handler);
}
NOTE: Either case you need to be able to replace the actual model with the proxied model at least for the duration of your test.
With another trick, you can find out who called which method of your model. Simply by accessing Thread.currentThread().getStackTrace() and retrieving the appropriate element.
Now puting all the pieces together:
InvocationLog.java
public final class InvocationLog {
private Method method;
private Object[] arguments;
private StackTraceElement caller;
public InvocationLog(Method method, Object[] arguments, StackTraceElement caller) {
this.method = method;
this.arguments = arguments;
this.caller = caller;
}
public Method getMethod() { return this.method; }
public Object[] getArguments() { return this.arguments; }
public StackTraceElement getCaller() { return this.caller; }
#Override
public String toString() {
return String.format("%s (%s): %s",
method == null ? "<init>" : method.getName(),
arguments == null ? "" : Arrays.toString(arguments),
caller == null ? "" : caller.toString());
}
}
ModelWatch.java
public final class ModelWatch {
private final Map<String, Object> modelProxy;
private final List<InvocationLog> logs = new ArrayList<>();
public ModelWatch(final Map<String, Object> model) {
modelProxy = proxy(model);
}
#SuppressWarnings("unchecked")
private Map<String, Object> proxy(final Map<String, Object> model) {
final InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method, args, Thread.currentThread().getStackTrace());
return method.invoke(model, args);
}
};
return (Map<String, Object>) Proxy.newProxyInstance(Map.class.getClassLoader(),
new Class<?>[] { Map.class }, handler);
}
private void log(Method method, Object[] arguments, StackTraceElement[] stack) {
logs.add(new InvocationLog(method, arguments, stack[3]));
// 0: Thread.getStackTrace
// 1: InvocationHandler.invoke
// 2: <Proxy>
// 3: <Caller>
}
public Map<String, Object> getModelProxy() { return modelProxy; }
public List<InvocationLog> getLogs() { return logs; }
}
To put it in use:
private Map<String, Object> actualModel = new HashMap<String, Object>();
private ModelWatch modelWatch = new ModelWatch(model);
private Map<String, Object> model = modelWatch.getModelProxy();
// Calls to model ...
modelWatch.getLogs() // Retrieve model activity
I want to mock "source" when the method "ProductAdapterService.adapt" is called by other class.
How to deal that? I really tried a lot of ways. Please help me. I am a new guy.Thanks a lot!
public class ProductAdapterService {
private final SearchParameter parameter;
private List<Festival> festivals;
public ProductAdapterService(SearchParameter parameter) {
this.parameter = parameter;
}
public SingleProduct adapt(SearchHit hit, boolean bidding) {
//I want to mock "source", I don't want to use "hit.getSource()"
Map<String, Object> source = hit.getSource();
SingleProduct sp = new SingleProduct();
sp.setId(TypeConverter.toInt(source.get(FieldName.PRODUCT_ID)));
sp.setName(TypeConverter.toString(source.get(FieldName.NAME)));
sp.setPrice(this.price(source.get(FieldName.PRICE), source.get(FieldName.PRICE_MAP), source.get(FieldName.FIRST_START_CITIES)));
sp.setLevel(TypeConverter.toInt(source.get(FieldName.PRODUCT_LEVEL)));
sp.setDepartureCityId(this.departureCity(source.get(FieldName.DEPARTURE_CITY_ID), source.get(FieldName.FIRST_START_CITIES)));
sp.setSaleMode(TypeConverter.toString(source.get(FieldName.SALE_MODE)));
sp.setBrandName(this.providerBrandName(source.get(FieldName.PROVIDER_BRAND)));
sp.setSaleCount(TypeConverter.toInt(source.get(FieldName.MONTHLY_ORDER)));
sp.setCommentCount(TypeConverter.toInt(source.get(FieldName.COMMENT_COUNT)));
sp.setCommentScore(TypeConverter.toFloat(source.get(FieldName.COMMENT_SCORE)));
sp.setBuType(BuType.GT);
sp.setType(this.productType(source.get(FieldName.SEARCH_TAB_TYPE_SHOW), sp.getSaleMode()));
sp.setSaleout(this.saleout(source.get(FieldName.NON_SALEOUT_CITIES), sp.getDepartureCityId()));
if (!sp.isSaleout()) {
sp.setFestival(this.festival(source.get(FieldName.FESTIVAL_IDS)));
}
System.out.println("sp.getName(): " + sp.getName());
return sp;
}}
And below is my test code:
public class TabSearcherTest0 {
#Test
public void test() {
SearchParameter parameter = SearchParameter.create();
Ghost.begin();
parameter.getFiltered().setTab(TabType.ALL);
parameter.getPoi().setKeyword("Spa");
parameter.getClient().setTrace(TraceMode.MAIN);
Map<String, Object> mapMock = new HashMap<String, Object>();
mapMock.put("productgroupid", "12877");
mapMock.put("productid", "5539739");
mapMock.put("firststartcitys", "[1, 2]");
mapMock.put("nonsaleoutcities", "[1, 2]");
mapMock.put("productdiamondlevel", "4");
mapMock.put("commentcount", "0");
mapMock.put("price", "0.0");
mapMock.put("name", "TestName");
mapMock.put("searchtabtypeshow", "1");
mapMock.put("comment", "0.0");
mapMock.put("salemode", "S");
mapMock.put("providerbrandid", "999999");
mapMock.put("departurecityid", "2");
// how to inject the map?
// ???
SearchModel model = SearchContext.createContext(parameter).search();
Ghost.end();
System.out.println(model);
}}
You are getting "mocking" the wrong way. You only used it when you can not use the real class implementation; but you need to control how some object reacts to methods calls to it.
Your method to test looks like:
public SingleProduct adapt(SearchHit hit, boolean bidding) {
//I want to mock "source", I don't want to use "hit.getSource()"
Map<String, Object> source = hit.getSource();
Wrong: you want to make sure that hit.getSource() is used. Because your production code is using is; and you write your unit tests to text that code. So you want that your production code does its "normal" thing.
So, the very simply solution here is:
#Test
public void testAdapt() {
SearchHit mockedHit = mock(SearchHit.class);
Map<String, Object> resonseForGetSource = new HashMap<>();
resonseForGetSource.put("productgroupid", "12877");
...
doReturn(resonseForGetSource).when(mockedHit.getSource());
ProductAdapterService underTest = ...
underTest.adapt(mockedHit, true);
... probably some asserts
or something alike (don't nail me on the doReturn/when details here)
What you can see here: your production code needs that map to do its job; so you just make sure that such a map object shows up in your production code.
And in case it would be possible to use a real SearchHit object (that you could configure with such a map); then using that would even be better than mocking that object.
You absolutely try to minimize your usage of mocking. You only use it to gain control over objects that are used during a certain test.
And beyond that: you are not clear about the scope of your unit testing. In order to test that one method, you dont need no ghosts. The unit test code you are showing simply doesn't make sense in the context of the class you are showing us here! Thus: you better step back and carefully look into "which units do I have" and "how to unit test exactly that unit X". You don't text "X" by testing "Y"!