I'm testing the following method:
private String getHomeStateCountry(Details aDetails, String aCountry) {
String homeState = Constants.BLANK_SPACE;
if (Constants.USA.equalsIgnoreCase((aCountry))) {
if (aDetails.getStateCountry() != null) {
homeState = aDetails.getStateCountry().getStateName();
}
} else {
if (aDetails.getStateCountry() != null) {
homeState = aDetails.getStateCountry().getCountryName();
}
}
return homeState;
}
When writing JUnits for this method, Is it pointless to set the stateName and countryName for each test(so if something goes wrong, e.g. the state is returned instead of the country, then the fail message provides a more accurate explanation etc) or should each test only set the value under test, i.e. if I'm testing for other than USA, only set countryName and check the returned value?
Related
I'm writing a junit test case for a method in the data access layer, how to stub/verify a complex query using mockito?
checked the following links on how to stub a complex query:
- https://howtodoinjava.com/hibernate/hibernate-criteria-queries-tutorial/
- https://github.com/MorphiaOrg/morphia/issues/933
none of them match my case, and the documentation does not say much about it
https://static.javadoc.io/org.mockito/mockito-core/2.8.9/index.html?org/mockito/Mockito.html
Actual code :
public List<Content> getContentByParams(String entity, String channelId, String sectionId,
Integer limit, String[] retrievedFields) {
Query<Content> query = this.createQuery();
if (StringUtils.isNotBlank(channelId) && StringUtils.isNotBlank(sectionId)) {
query.and(query.criteria("name").equalIgnoreCase(entity),
query.criteria("channel").equal(channelId),
query.criteria("section").equal(sectionId));
System.out.println("after===============");
}
if (retrievedFields != null && retrievedFields.length > 0) {
System.out.println("retrieved fields");
for (String field : retrievedFields) {
query.project(field, true);
}
}
if (limit == null) {
limit = 4;
}
FindOptions findOptions = new FindOptions().limit(limit);
return query.asList(findOptions);
}
Test case :
public void getContentByEntitiesAndPrimaryChannelSection() {
FieldEnd<Criteria> mockFieldEndEntity = mock(FieldEnd.class);
FieldEnd<Criteria> mockFieldEndChannel = mock(FieldEnd.class);
FieldEnd<Criteria> mockFieldEndSection = mock(FieldEnd.class);
// doReturn(mockFieldEndEntity).when(query).criteria("name");
// doReturn(mockFieldEndChannel).when(query).criteria("channel");
// doReturn(mockFieldEndSection).when(query).criteria("section");
contentDAO.getContentByParams(entity, "channel_3", "section_3", 10, mockFields);
for (String field : mockFields) {
verify(query).project(field, true);
}
ArgumentCaptor<FindOptions> argument = ArgumentCaptor.forClass(FindOptions.class);
verify(query).asList(argument.capture());
FindOptions findOptions = argument.getValue();
assertEquals(10, findOptions.getLimit());
PowerMockito.verifyStatic(MongoQueryUtil.class, times(1));
}
I am unsure on how to add a test for the query creation part with the test current status it passes but it is not testing the query creation.
any help will be appreciated or if there is a documentation for it somewhere.
I have an activity 'B'. I have 2 more activities A and C. Both the activities lead to B. But i pass different Data from A and C. So while fetching
String dataFromA = getIntent.getStringExtra("SomethingA");
String dataFromC = getIntent.getStringExtra("SomethingC");
How to not get an error. I wont know from where the user is getting to activity B So how do i add an If statement or seomthing to not get an error while fetching as Either line A or C will get a NullPOinterException
You can use hasExtra method to check if that String exists.
if (getIntent().hasExtra("SomethingA")) {
String dataFromA = getIntent.getStringExtra("SomethingA");
} else if (getIntent().hasExtra("SomethingC")) {
String dataFromC = getIntent.getStringExtra("SomethingC");
}
You can try this code.
Bundle arguments = getArguments();
if (arguments != null){
if (arguments.containsKey("SomethingA")) {
String somethingA = arguments.getString("SomethingA");
if (TextUtils.isEmpty(somethingA)){
// Your codes comes here
}
}
}
Bundle (arguments) can be null if there is no data passed.
To check if string is empty or not use below code :
if(TextUtils.isEmpty(yourString))
{
// String empty
}
else
{
// string not empty
}
In your case you check it as :
if (getIntent()!=null && getIntent().getStringExtra!=null )
{
if (getIntent().hasExtra("SomethingA") && getIntent().hasExtra("SomethingB"))
String dataFromA = getIntent.getStringExtra("SomethingA");
String dataFromB = getIntent.getStringExtra("SomethingB");
}
I am writing unit tests for he below code. but coverage is missing for the below lines of code. I am not sure how can we cover the below lines.My research didnt help.
public DetailsResponse mapRow(ResultSet resultSet, int num) throws SQLException {
DetailsResponse DetailsResponse = new DetailsResponse();
String[] responseElements = null;
String response = resultSet.getString(1);
//coverage missing for below line
if (response != null && response.indexOf(",") != -1) {
responseElements = response.split(",");
}
//coverage missing for below line
if (responseElements != null && responseElements.length > 0) {
//coverage missing for below line
String id = StringUtils.isNotBlank(responseElements[0]) ? responseElements[0].replace("(", "") : "";
The commented lines are missing from the coverage., how can i test them?
Since this is a public method and you are trying to write a unit test, not an integration test, you can simply setup a ResultSet object. In doing so, you can set the object so that both conditions will get covered.
#Test
public void test(){
// SETUP
ResultSet resultSet = // setup ResultSet to return what looks like a comma separated list.
// TEST
DetailsResponse out = service. mapRow(resultSet, someNum);
// VERIFY / ASSERT
// some assert(s) on out
}
I'm stuck on the very last part of my homework. I have to return an Agent value, but for some reason I keep getting an error saying that "This method must return type Agent", even though what I am returning is an Agent. Any help would be greatly appreciated.
import java.io.File;
import java.util.HashMap;
import jeff.ini.Ini;
public class ConfigLoader
{
private Ini _ini;
private HashMap<String, Space> _spaces = new HashMap<String, Space>();
private HashMap<String, Portal> _portals = new HashMap<String, Portal>();
private HashMap<String, Agent> _agents = new HashMap<String, Agent>();
public ConfigLoader(File iniFile)
{
_ini = new Ini(iniFile);
}
public Agent buildAll()
{
_buildSpaces();
_buildPortals();
_buildExits();
_buildDestinations();
_buildAgents();
return _selectStartAgent();
}
private void _buildSpaces(){
for(String spaceName : _ini.keys("spaces")){
String descrip= _ini.get("spaces", spaceName);
String image= _ini.get("images", "images");
Space space1= new Space(spaceName, descrip, image, null);
_spaces.put(spaceName, space1);
}
}
private void _buildPortals(){
for(String portalName : _ini.keys("portals")){
String descrip= _ini.get("portal", portalName);
Portal portal1=new Portal(portalName, descrip, null);
_portals.put(portalName, portal1);
}
}
private void _buildExits(){
for(String spaceName : _ini.keys("exits")){
String spaceExit = _ini.get("exits", spaceName);
Space space = _spaces.get(spaceName);
Portal exit = _portals.get(spaceExit);
space.setPortal(exit);
}
}
private void _buildDestinations(){
for(String portalName : _ini.keys("destinations")){
String destination = _ini.get("destinations", portalName);
Space des = _spaces.get(destination);
if(des == null){
System.out.print("ERROR");
System.exit(1);
}
else{
Portal portal = _portals.get(portalName);
portal.setDestination(des);
}
}
}
private void _buildAgents(){
for(String agentName : _ini.keys("agents")){
String agent = _ini.get("agents" , agentName);
Space space = _spaces.get(agent);
if(space == null){
System.out.print("ERROR");
System.exit(1);
}
else{
Agent a = new Agent(space, agentName);
_agents.put(agentName, a);
}
}
}
private Agent _selectStartAgent(){
for(String agentName : _ini.keys("start")){
String agent = _ini.get("start" , agentName);
Agent agent1 = _agents.get(agent);
if(agent == null){
System.out.print("ERROR");
System.exit(1);
}
else{
return agent1;
}
}
}
}
A method should return a value in all the different execution path. You are returning a value only in else block, which means in case when else block is not executed the value will not be returned and hence compiler complains for it. Make sure that you return a value in all different execution path, when if is not executed, when else is not executed, when for loop itself is not executed.
The key is that all execution paths must return a value of type Agent, which could be null. The calling method must, as usual, check whether the returned value is null.
Now let's look at what are missing:
The if branch does not return a value, instead it abruptly exits.
If the for loop is never entered, the method does not return anything either.
With all those fixed, the entire code could be something like:
for (String agentName : _ini.keys("start")){
String agent = _ini.get("start" , agentName);
Agent agent1 = _agents.get(agent);
if (agent == null){
System.out.print("ERROR");
return null;
} else {
return agent1;
}
return null;
}
The problem with your _selectStartAgent method is that a return isn't executed in all cases. You do call System.exit(1) inside this method, but the compiler doesn't care; it sees that as another method call. Even if it won't return because the JVM will be exited, the compiler still requires a return in the case where agent is null.
You could just place a return null; after System.exit(1). However, this method shouldn't be handling an error. It just needs to report the error. Just have it return null (or have it throw an exception).
if(agent == null){
return null;
// or
// throw an exception here
}
The method that calls _selectStartAgent should check for null (or handle the exception, depending on which you choose).
Additionally, the compiler doesn't assume that there will be an iteration of any for loop. There is no return there either. You can place a return statement after the for loop, to ensure that there is a return when there is no iteration of the for loop.
I believe it has to do with if your for loop doesn't have anything to loop through. In that case, you have no return statement.
Try adding return null after the for loop.
private Agent _selectStartAgent(){
for(String agentName : _ini.keys("start")){
String agent = _ini.get("start" , agentName);
Agent agent1 = _agents.get(agent);
if(agent == null){
System.out.print("ERROR");
System.exit(1);
}
else{
return agent1;
}
}
return null;
}
I have a java code in which there are multiple return statements in a single method. But for code cleaning purpose, I can have only one return statement per method. What can be done to overcome this.
Here is a method from my code:-
public ActionForward login(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Kill any old sessions
//request.getSession().invalidate();
DynaValidatorForm dynaform = (DynaValidatorForm)form;
// validate the form
ActionErrors errors = form.validate(mapping, request);
if(!errors.isEmpty()) {
this.saveErrors(request, errors);
return mapping.getInputForward();
}
// first check if token is set
if(!isTokenValid(request, true)) {
String errmsg="There was a problem with your login. Please close your browser then reopen it and try again. Make sure to click the Login button only ONCE.";
request.setAttribute("errormessage", errmsg);
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
// check the form for input errors
String errmsg = checkInput(form);
if (errmsg != null) {
request.setAttribute("errormessage", errmsg);
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
// no input errors detected
String resumekey = null;
// check for valid login
ObjectFactory objFactory = ObjectFactory.getInstance();
DataAccessor dataAccessor = objFactory.getDataAccessor();
request.setCharacterEncoding("UTF-8");
String testcode = dynaform.getString("testcode").trim();
String studentname = dynaform.getString("yourname").trim();
String password = dynaform.getString("password").trim();
// 4/3/07 - passwords going forward are ALL lower case
if (!CaslsUtils.isEmpty(password)) {
password = password.toLowerCase();
}
try{
resumekey = new String(studentname.getBytes("ISO-8859-1"),"UTF-8");
} catch (Exception e) {
log_.error("Error converting item content data to UTF-8 encoding. ",e);
}
String hashWord = CaslsUtils.encryptString(password);
// Make sure this is short enough to fit in the db
if (hashWord.length() > ConstantLibrary.MAX_PASSWORD_LENGTH) {
hashWord = hashWord.substring(0, ConstantLibrary.MAX_PASSWORD_LENGTH);
}
Login login = dataAccessor.getLogin(testcode, hashWord, false);
if (login == null || !login.getUsertype().equals(Login.USERTYPE_SUBJECT)) {
request.setAttribute("errormessage", "Incorrect test code or password.");
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
// Check if the login has expired
if (login.getLoginexpires() != null && login.getLoginexpires().before(new Date())) {
request.setAttribute("errormessage", "Your login has expired.");
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
// Check if the password has expired
if (login.getPasswordexpires() != null && login.getPasswordexpires().before(new Date())) {
request.setAttribute("errormessage", "Your login password has expired.");
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
HttpSession session = request.getSession();
session.setAttribute(ConstantLibrary.SESSION_LOGIN, login);
session.setAttribute(ConstantLibrary.SESSION_STUDENTNAME, studentname);
List<Testtaker> testtakers = null;
try {
//invalidate the old session if the incoming user is already logged in.
synchronized(this){
invalidateExistingSessionOfCurrentUser(request, studentname, testcode);
testtakers = dataAccessor.getTesttakersByResumeKey(studentname, login);// Adding this code to call getTesttakersByResumeKey instead of getTesttakers to improve the performance of the application during student login
}
} catch (Exception e) {
log.error("Exception when calling getTesttakers");
CaslsUtils.outputLoggingData(log_, request);
throw e;
}
session = request.getSession();
if(testtakers!=null)
{
if(testtakers.size() == 0) {
// new student -> start fresh
log_.debug("starting a fresh test");
// if this is a demo test, skip the consent pages and dump them directly to the select test page
if (login.getTestengine().equals(Itemmaster.TESTENGINE_DEMO)) {
return mapping.findForward("continue-panel");
}
}
// send them to fill out the profile
// check for custom profiles
String[] surveynames = new String[4];
List<Logingroup> logingroups = dataAccessor.getLoginGroupsByLogin(login.getLoginid());
for(Logingroup logingroup : logingroups) {
Groupmaster group = logingroup.getGroupmaster();
log_.debug(String.format("group: {groupid: %d, grouptype: %s, groupname: %s}", new Object[] {group.getGroupid(), group.getGrouptype(), group.getName()}));
Set<Groupsurvey> surveys = group.getGroupsurveys();
if(surveys.size() > 0) {
// grab the first (and only) one
Groupsurvey survey = surveys.toArray(new Groupsurvey[0])[0];
if(group.getGrouptype().equalsIgnoreCase(Groupmaster.GROUPTYPE_CLASS)) {
surveynames[0] = survey.getSurveyname();
} else if (group.getGrouptype().equalsIgnoreCase(Groupmaster.GROUPTYPE_SCHOOL)){
surveynames[1] = survey.getSurveyname();
} else if (group.getGrouptype().equalsIgnoreCase(Groupmaster.GROUPTYPE_DISTRICT)){
surveynames[2] = survey.getSurveyname();
} else if (group.getGrouptype().equalsIgnoreCase(Groupmaster.GROUPTYPE_STATE)){
surveynames[3] = survey.getSurveyname();
}
}
}
// match the most grandular survey
for(int i=0; i < surveynames.length; ++i) {
if(surveynames[i] != null) {
saveToken(request);
return mapping.findForward("student-profile-"+surveynames[i]);
}
}
// no custom profile, send them to the default
saveToken(request);
return mapping.findForward("student-profile");
}
// get the set of availible panels
Set<Panel> availiblePanels = dataAccessor.getAvailiblePanels(login, studentname);
if(availiblePanels.size() == 0) {
// no panels availible. send to all done!
log_.debug(String.format("No panels availible for Login:%s with resumekey:%s", login.toString(), studentname));
session.setAttribute("logoutpage", true);
resetToken(request);
return mapping.findForward("continue-alldone");
}
//Eventum #427 - Prevent test takers from retaking a finished test.
TestSubjectResult testSubjecResult=dataAccessor.getTestSubjectResult(login, resumekey);
if(testSubjecResult != null){
if(testSubjecResult.getRdscore() != null && testSubjecResult.getWrscore() != null && testSubjecResult.getLsscore() != null && testSubjecResult.getOlscore() != null){
if(testSubjecResult.getRdscore().getFinishtime() != null && testSubjecResult.getWrscore().getFinishtime() != null && testSubjecResult.getLsscore().getFinishtime() != null && testSubjecResult.getOlscore().getFinishtime() != null){
log_.debug(String.format("Already completed all the Skill Tests.", login.toString(), studentname));
session.setAttribute("logoutpage", true);
resetToken(request);
return mapping.findForward("continue-alldone");
}
}
}
// get a list of resumeable testtakers
List<Testtaker> resumeableTesttakers = new ArrayList<Testtaker>();
for(Testtaker testtaker : testtakers) {
if(testtaker.getPhase().equals(ConstantLibrary.PHASE_GOODBYE)) {
// testtaker is done with test. skip.
continue;
}
if(testtaker.getCurrentpanelid() == null) {
// testtaker is the profile testtaker
continue;
}
resumeableTesttakers.add(testtaker);
}
// sort them from least recent to latest
Collections.sort(resumeableTesttakers, new Comparator<Testtaker>() {
#Override
public int compare(Testtaker o1, Testtaker o2) {
// TODO Auto-generated method stub
//return 0;
return new CompareToBuilder()
.append(o1.getLasttouched(), o2.getLasttouched())
.toComparison();
}
});
if(resumeableTesttakers.size() == 0 && availiblePanels.size() > 0) {
// nobody is resumeable but there are panels left to take
// send them to the panel choice
// TODO: This is probably a misuse of Struts.
log_.info("No resumeable testtakers. Sending to panel select");
saveToken(request);
ActionForward myForward = (new ActionForward("/do/capstartpanel?capStartPanelAction=retest&lasttesttakerid="
+ testtakers.get(0).getTesttakerid(), true));
return myForward;// mapping.findForward(ConstantLibrary.FWD_CONTINUE + "-panel");
} else {
// grab the one most recently created and take their test
log_.info(String.format("Resuming with choice of %d testtakers", resumeableTesttakers.size()));
// we're forwarding to resume at this point, so we should do the some of the initialization
// that would have happened if we were still using getTesttaker() instead of getTesttakers() above.
session.setAttribute(ConstantLibrary.SESSION_LOGIN, login);
session.setAttribute(ConstantLibrary.SESSION_TESTTAKER, resumeableTesttakers.get(resumeableTesttakers.size()-1));
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_RESUME);
}
}
It's not a worth changing multiple returns to a single return statement per method. Actually, that will unnecessarily increase the burden of storing the result in a local variable and then making the return finally,
ActionForward result = null;
//scenario 1
result = ...
//scenario 2
result = ...
//scenario 3
result = ...
//finally
return result;
Hope this helps, but, it doesn't make much sense to me
As pointed out by others, having a single return statement does not necessarily make your code cleaner. However, in this case splitting up the method in smaller pieces probably makes the code more readable.
For example, this part:
// first check if token is set
if(!isTokenValid(request, true)) {
String errmsg="There was a problem with your login. Please close your browser then reopen it and try again. Make sure to click the Login button only ONCE.";
request.setAttribute("errormessage", errmsg);
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
// check the form for input errors
String errmsg = checkInput(form);
if (errmsg != null) {
request.setAttribute("errormessage", errmsg);
saveToken(request);
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
could be replaced by introducing two methods and using those to write:
If(tokenNotSet() || formHasErrors()){
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
}
By doing this on multiple places the structure of the algorithm becomes more clear, possibly giving you more insight in how this code could be refactored to adhere to your coding guidelines.
I would set a an action forward variable at the start of the method.
ActionForward actionForwardToReturn = null;
Then replace each of these two lines
return mapping.getInputForward();
return mapping.findForward(ConstantLibrary.FWD_CONTINUE);
with these two lines :
actionForwardToReturn = mapping.getInputForward()
actionForwardToReturn = mapping.findForward(ConstantLibrary.FWD_CONTINUE);
finally return the variable.
return actionForwardToReturn;
This shouldn't be too difficult :)
On a side note... (actually the orginal answer to the question) :
Multiple return statements can make it hard to debug code.
I personally would have just one action object that you return at the end of the method. The benefit of this, is that i can put a break point right on the return statement and look at exactly what that object is.
Any logging or other cross cutting concern I would want to add later, would only have to be done at one point. Otherwise I would have to add a log statement to every line where you are returning.
The complexity added to a method in an attempt to remove multiple return statements is many a times not worth it, especially in a method such as yours.There's nothing wrong with using them in this case.
Like user3580294 there's nothing wrong with multiple return statements. However you could combine the last two if statements since they are essentially returning the same thing.
Use #Octopus 's method if you absolutely have to have one return statement