How to test a method that calls different methods inside? - java

I have a method to unit test called addSong(song,userId) in service class. I am calling three methods inside it from Dao class. I am using Easy mock to mock dao class. In the setup I first mock all the methods I am calling in addSong(song,userId), and then calling the service.addsong(song,userId) method fot test.
But I am getting the following error:
Java.lang.IllegalStateException: missing behavior definition for the preceding method call:
MusicPlayerDao.addSong(song)
Usage is: expect(a.foo()).andXXX()
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:42)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at service.MusicPlayerDao$$EnhancerByCGLIB$$45bc3ca1.addSong(<generated>)
at service.MusicPlayerServiceImpl.addSong(MusicPlayerServiceImpl.java:43)
at AddSongTest.addSongs(AddSongTest.java:90)
Here is my code:
private void addSongSetup() throws SQLException{
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
EasyMock.expect(this.dao.addSong(song)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.addGenre(genre, 1)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.addAlbum(album, 1)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.userIdSongsMapping(1,1)).andReturn(1).anyTimes();
}
#Test
public void addSongs(){
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
try {
System.out.println(this.dao.addSong(song));
boolean status = this.service.addSong(song, 1);
assertEquals(true,status);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My addSong method in service class:
public boolean addSong(Song song, int userId) throws Exception {
MusicPlayerDaoInterface musicPlayerDao = MusicPlayerDao.getInstance();
boolean status = false;
int songId = 0;
TransactionManager transactionManager = TransactionManagerImpl
.getInstance();
try {
if (song != null) {
if (song.getTitle() != null) {
transactionManager.begin();
songId = musicPlayerDao.addSong(song);
song.setSongId(songId);
if (song.getGenre() != null
&& song.getGenre().getGenreName() != null) {
musicPlayerDao.addGenre(song.getGenre(),
song.getSongId());
}
if (song.getAlbum() != null
&& song.getAlbum().getAlbumName() != null) {
musicPlayerDao.addAlbum(song.getAlbum(),
song.getSongId());
}
if (userId != 0 && songId != 0) {
musicPlayerDao.userIdSongsMapping(userId,
song.getSongId());
}
transactionManager.commit();
status = true;
}
}
} catch (SQLException | RollbackException | HeuristicMixedException
| HeuristicRollbackException e) {
transactionManager.rollback();
status = false;
throw e;
}
return status;
}
I don't know were I am going wrong. Please help.

I think you are missing a EasyMock.replay statement after you record the expected behaviour. Something like
EasyMock.replay(this.dao);
From the EasyMock guide:
To get a Mock Object, we need to
create a Mock Object for the interface we would like to simulate
record the expected behavior
switch the Mock Object to replay state

try removing the following lines from the addSongs test case:
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
I assume that addSongSetup is invoked before addSongs (e.g.; #Before). You are reassigning values to your variables album, genre and song in addSong, which, I suppose, EasyMock cannot match to your mock setup in addSongSetup as (depending on how EasyMock implemented this)
you forgot to implement hashcode or equals in Song, Album, Genre or,
EasyMock uses Object identity (i.e., reference comparison)
I guess it's 1.

Related

spring bean is null in mockito test

I'm using spring 5 and mockito, but in a test process i have a problem where my bean is done null and i get a NullPointerException, how can i fix it?
infact, my SpringContext.getBean returns null but it work correctly when the application is in runtime mode.
java.lang.NullPointerException
at com.novinkish.batch.ParallerMakerTest.testSendData(ParallerMakerTest.java:53)
.
.
Caused by: java.lang.NullPointerException
at com.novinkish.batch.util.SpringContext.getBean(SpringContext.java:14)
my test class is like this:
#RunWith(MockitoJUnitRunner.class)
public class ParallerMakerTest {
#Mock
private CommonRestCallerImpl restCallerImpl;
#Test
public void testSendData(){
PersonDTO personDTO_1 = new PersonDTO("1111111111", "name_1", "L_name_1", "2000/05/09", (short) 0);
PersonDTO personDTO_2 = new PersonDTO(4646L, "1111111111", "name_1", "L_name_1", "2000/05/09", (short) 1);
List<PersonDTO> resultDtoList = new ArrayList<PersonDTO>();
try {
when(restCallerImpl.callService(ServiceNameJNDI.SAVE_PERSON, personDTO_1, PersonDTO.class)).thenReturn(personDTO_2);
} catch (Exception e) {
e.printStackTrace();
}
ForkJoinPool pool = new ForkJoinPool();
PersonSessionParallerMaker maker = new PersonSessionParallerMaker(restCallerImpl, Arrays.asList(personDTO_1));
pool.execute(maker);
try {
pool.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
resultDtoList = (List<PersonDTO>) pool.invoke(maker);
Assert.assertNotNull(resultDtoList);
Assert.assertEquals(1, ((PersonDTO)resultDtoList.get(0)).getStatus().intValue());
}
and my class is:
public class PersonSessionParallerMaker extends RecursiveTask {
private CommonRestCaller restCaller;
private List<PersonDTO> initList = new ArrayList<PersonDTO>();
private List<PersonDTO> resultList = new ArrayList<PersonDTO>();
private PersonDTO target;
public PersonSessionParallerMaker(CommonRestCaller restCaller, List<PersonDTO> initList) {
this.initList = initList;
this.restCaller = restCaller;
}
public PersonSessionParallerMaker(PersonDTO target) {
this.target = target;
}
#Override
protected Object compute() {
/*MASTER Thread*/
if (target == null) {
for (PersonDTO personDTO : initList) {
/*CREATE FORK (SUB THREAD)*/
PersonSessionParallerMaker parallerMaker = new PersonSessionParallerMaker(personDTO);
invokeAll(parallerMaker);
resultList.add((PersonDTO) parallerMaker.join());
}
return resultList;
} else if (target.getStatus() == 0) {
callService();
return target;
} else
return null;
}
public void callService() {
System.out.println("1.restCaller = " + restCaller);
/*For Unit Test*/
if (restCaller == null) {
System.out.println("2.restCaller = " + restCaller);
restCaller = (CommonRestCaller) SpringContext.getBean(CommonRestCallerImpl.class);
System.out.println("3.restCaller = " + restCaller);
}
try {
System.out.println("target.toString() = " + target.toString());
target = (PersonDTO) restCaller.callService(ServiceNameJNDI.SAVE_PERSON, target, PersonDTO.class);
} catch (Exception e) {
e.printStackTrace();
target.setStatus((short) 2);
}
}
}
You are mixing up unit testing and integration testing here.
What you have written, is a unit test. Unit tests run - per definiton - isolated from the whole application, therefore you have no access to the application context. The purpose of a unit test is to test one specific class.
If you want to test the behaviour of your whole application, you have to write an integration test.
See https://www.baeldung.com/spring-boot-testing#integration-testing-with-springboottest for further reading.

How to modify the input parameter of void method from the mocked method with mockito answer

I have a class A as
Class A{
private static final String ANON_DIR = "/webapps/worldlingo/data/anonymizer/";
private static final String NO_ANON = "noanonymize";
public String first(String text, String srclang, Map dictTokens) {
Set<String> noAnonymize = new HashSet<String>();
second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
String value;
if(noAnonymize.contains("test")){
value = "test1";
}
else {
value = "test";
}
return value;
}
where ANON_DIR and NO_ANON is static final value. This class has function first and function second .The first function has a calling method in it which calls second function. The second function is void function which takes static fields as parameter.
Second function is just the file read function with the path provided as
public void second (Set<String> hashSet, String path, String lang , String type) {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(path);
br = new BufferedReader(fr);
String Line;
while ((Line = br.readLine()) != null) {
hashSet.add(Line);
}
} catch (IOException e) {
log.error("Anonymizer: Unable to load file.", e);
} finally {
try {
if (fr != null) {
fr.close();
}
if (br != null) {
br.close();
}
} catch (IOException e) {
log.error("Anonymizer : An error occured while closing a resource.", e);
}
}
}
}
Now I am trying to test the function first using mockito. I am trying update the passed first argument (list parameter) i.e noAnonymize in second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
public void testfirst() throws Exception {
Anonymizer mock = PowerMockito.mock(Anonymizer.class);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
List<String> args = invocation.getArgumentAt(0,List.class);
args.add("a");
args.add("b");
return null; // void method, so return null
}
}).when(mock).readNoAnonymizeFile(Mockito.anySet(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString());
Method anonymizeNames = anon.getClass().getDeclaredMethod("anonymizeNames_test", String.class, String.class, Map.class);
String srcLang = "MSFT_EN";
Map mapTokens = new HashMap();
String result = (String) anonymizeNames.invoke(anon,"I am David",srcLang,mapTokens);
}
PROBLEM:
I am not able to mock the void second method to update list with value a and b. How can I have the mockto test case to update parameter in void method.
When unit testing a class, you test it through its public methods. If you can't test the class sufficiently through its public methods, it needs re-factored.
In this case, you're trying to unit test a private method for an edge case that doesn't exist. Why even provide the constant as a parameter? Why not reference it directly in the private method and save passing an argument? Instead, you could write:
fr = new FileReader(ANON_DIR + NO_ANON);
EDIT
After Laxmi and I had a discussion we came up with a solution using constructor based dependency injection and changing the void method to return Set<String>. This let us test in isolation and mock easily.

JASPIC Wildfly 9 validateRequest with session

Based on this Jaspic Example I wrote the following validateRequest method for a ServerAuthModule:
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
Subject serviceSubject) throws AuthException {
boolean authenticated = false;
final HttpServletRequest request =
(HttpServletRequest) messageInfo.getRequestMessage();
final String token = request.getParameter("token");
TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();
Callback[] callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, (TokenPrincipal) null) };
if (principal != null) {
callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, principal) };
authenticated = true;
} else {
if (token != null && token.length() == Constants.tokenLength) {
try {
principal = fetchUser(token);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
callbacks = new Callback[]
{
new CallerPrincipalCallback(clientSubject, principal),
new GroupPrincipalCallback(clientSubject,
new String[] { "aRole" })
};
messageInfo.getMap().put("javax.servlet.http.registerSession", "TRUE");
authenticated = true;
}
}
if (authenticated) {
try {
handler.handle(callbacks);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
return SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
This works as expected, for the first call of an ejb with #RolesAllowed("aRole") but for the next call this does not work at all. Wildfly denies it with this error message:
ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation
failed on component TestEJB for method public java.lang.String
com.jaspic.security.TestEJB.getPrincipalName():
javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User
If I guess right, the error occures in:
org.jboss.as.security.service.SimpleSecurityManager line 367 of wilfly's source code, due to line 405, in which credential is checked, but seems to be null.
This seems equal in Wildfly 8/9/10CR (other versions not tested).
Again I'm not sure, if I'm doing it wrong, or if this is the same bug as
https://issues.jboss.org/browse/WFLY-4626 ? And is it a bug at all, or is it expected behavior?
This sounds like a bug to me as well, as the caller identity (caller / group Principals) appears to be retained in subsequent calls to the web, yet not to the EJB container. My own JASPIC classes (which function properly on GlassFish 4.1) fail for the same reason on WildFly 9.0.2.Final and 10.0.0.CR4 when used along with a plain Servlet and an SLSB, even with the latter marked #PermitAll.
As I'm myself unfamiliar with WildFly security internals I can not assist you in that respect. Unless you can get this patched, the sole SAM-level workaround I can think of for the time being would be to not use the javax.servlet.http.registerSession callback property that seemingly triggers the problem, but instead have the CallbackHandler register both the caller Principal and its groups on every validateRequest(...) invocation. If applicable to your use case, you may wish to attach that information to the HttpSession so as to speed up the process a bit; otherwise repeat from scratch. So, for example:
public class Sam implements ServerAuthModule {
// ...
#Override
public AuthStatus validateRequest(MessageInfo mi, Subject client, Subject service) throws AuthException {
boolean authenticated = false;
boolean attachAuthnInfoToSession = false;
final String callerSessionKey = "authn.caller";
final String groupsSessionKey = "authn.groups";
final HttpServletRequest req = (HttpServletRequest) mi.getRequestMessage();
TokenPrincipal tp = null;
String[] groups = null;
String token = null;
HttpSession hs = req.getSession(false);
if (hs != null) {
tp = (TokenPrincipal) hs.getAttribute(callerSessionKey);
groups = (String[]) hs.getAttribute(groupsSessionKey);
}
Callback[] callbacks = null;
if (tp != null) {
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
}
else if (isValid(token = req.getParameter("token"))) {
tp = newTokenPrincipal(token);
groups = fetchGroups(tp);
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
attachAuthnInfoToSession = true;
}
if (authenticated) {
try {
handler.handle(callbacks);
if (attachAuthnInfoToSession && ((hs = req.getSession(false)) != null)) {
hs.setAttribute(callerSessionKey, tp);
hs.setAttribute(groupsSessionKey, groups);
}
}
catch (IOException | UnsupportedCallbackException e) {
throw (AuthException) new AuthException().initCause(e);
}
return AuthStatus.SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
// ...
#Override
public void cleanSubject(MessageInfo mi, Subject subject) throws AuthException {
// ...
// just to be safe
HttpSession hs = ((HttpServletRequest) mi.getRequestMessage()).getSession(false);
if (hs != null) {
hs.invalidate();
}
}
private boolean isValid(String token) {
// whatever
return ((token != null) && (token.length() == 10));
}
private TokenPrincipal newTokenPrincipal(String token) {
// whatever
return new TokenPrincipal(token);
}
private String[] fetchGroups(TokenPrincipal tp) {
// whatever
return new String[] { "aRole" };
}
}
I tested the above on the aforementioned WildFly versions and in the aforementioned fashion (i.e. with a single Servlet referencing a single SLSB marked #DeclareRoles / method-level #RolesAllowed) and it seems to work as expected. Obviously I cannot guarantee that this approach will not fail in other unexpected ways.
See also:
[WFLY-4625]
[SECURITY-744]
[SECURITY-745]

Recursive function not working for to get innermost exception message

I have written this method
private string FindInnerExceptionMessage(Exception ex)
{
string exceptionMsg = string.Empty;
if (ex.InnerException == null)
{
exceptionMsg = ex.Message;
}
else
{
ex = ex.InnerException;
FindInnerExceptionMessage(ex);
}
return exceptionMsg;
}
However, after that FindInnerExceptionMessage it is stepping to return exceptionMsg and not logging the exact exception message
You don't actually assign the return value of your recursive call to anything. As a result, your first call will return String.Empty because the value of FindInnerExceptionMessage(ex.InnerException) is never assigned as the return value (unless the exception passed to the first call has no inner exception, in which case it will work). Try something like this:
private string FindInnerExceptionMessage(Exception ex)
{
string exceptionMsg = string.Empty;
if (ex.InnerException == null)
{
exceptionMsg = ex.Message;
}
else
{
exceptionMsg = FindInnerExceptionMessage(ex.InnerException);
}
return exceptionMsg;
}

ClassCastException error

I am doing one android application, for that I used com.android.internal API's. They are Call.java, CallManger.java. For these classes I created subclass for Call.java. You can find these two classes here http://hi-android.info/src/com/android/internal/telephony/Call.java.html and http://hi-android.info/src/com/android/internal/telephony/CallManager.java.html.
Subclass of Call.java is:
public class MyCall extends Call{
1. CallManager cm = CallManager.getInstance();
2. Phone.State state;
3.
4. Phone mDefaultPhone;
5. private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
6. List<Call> ringingCall;
7.
8. #Override
9. public List<Connection> getConnections() {
10.
11.
12. state = cm.getState();
13. ringingCall = cm.getForegroundCalls();
14. System.out.println("**inside getConnections="+state);
15. System.out.println("**inside getConnections="+ringingCall);
16. if ( ringingCall == null) {
17.
18. System.out.println("**call is null***");
19. return emptyConnections;
20. }
21. else
22. {
23. System.out.println("**call is not null***");
24. return ((Call) ringingCall).getConnections();
}
}
#Override
public Phone getPhone() {
// TODO Auto-generated method stub
return null;
}
#Override
public void hangup() throws CallStateException {
// TODO Auto-generated method stub
}
#Override
public boolean isMultiparty() {
// TODO Auto-generated method stub
return false;
}
public Connection
getEarliestConnection() {
List l;
long time = Long.MAX_VALUE;
Connection c;
Connection earliest = null;
l = getConnections();
if (l == null) {
return null;
}else if ( l.size() == 0)
{
return null;
}
for (int i = 0, s = l.size() ; i < s ; i++) {
c = (Connection) l.get(i);
long t;
t = c.getCreateTime();
if (t < time) {
earliest = c;
time = t;
}
}
return earliest;
}
}
I called instance of CallManger Like this:
CallManager cm = CallManager.getInstance();
Bcoz this is a final modifier class. My another class is CallUpdate.java.
public class CallUpdate {
Call myCall = new MyCall();
Connection myConn = new MyConnection();
CallManager cm = CallManager.getInstance();
public Object getCallFailedString(){
myConn = myCall.getEarliestConnection();
System.out.println("myConn is ******"+myConn);
System.out.println("myCall is ******"+myCall);
if(myConn == null){
System.out.println("myConn is null ******");
return null;
}
else
{
Connection.DisconnectCause cause = myConn.getDisconnectCause();
System.out.println("myconn is not null ******"+cause);
}
}
I am getting myConn value is null. For this I added some piece of code in getConnection method of MyCall class to get a non-null value of myConn. i.e
state = cm.getState();
ringingCall = cm.getForegroundCalls();
System.out.println("**inside getConnections="+state);
System.out.println("**inside getConnections="+ringingCall);
if ( ringingCall == null) {
System.out.println("**call is null***");
return emptyConnections;
}
else
{
System.out.println("**call is not null***");
return ((Call) ringingCall).getConnections();
}
But it is throwing ClassCastException error on Line No:24 and on line
l = getConnections();.
And also I need at least one outgoing call to get a value of myConn. How to resolve this error?
Thx in advance.
ringingCall is a List<Call> - not a single call. You probably want something like:
if (ringingCall != null && !ringingCall.isEmpty()) {
Call call = ringingCall.get(0);
// Use call
}
... but you should also consider what you want to do if there's more than one call.
In general, if you find yourself casting that's because you think you know better than the compiler. It should always at least make you think - and in the case where you want a Call but you've got a List<Call>, the natural approach should be to use an element from the list.
It's not clear whether you really want to be subclassing Call in the first place, to be honest.

Categories

Resources