Why #Stateless #WebService is stateful? - web-services

With a web service defined like #Stateless
import javax.ejb.Stateless;
import javax.jws.WebService;
#Stateless
#WebService(serviceName = "TestService")
public class TestService {
int counter = 0;
public int getCounter() {
return counter++;
}
}
Why 'counter' is increased with each request and does not return always 0?

Because with #Stateless you're telling the container that you are not holding any state, but you do hold state.
With #Stateless the container only creates one instance of the bean, because there's no need to create more.
You might want to read a bit more about JEE and what the annotations mean: http://theopentutorials.com/tutorials/java-ee/ejb3/session-beans/slsb/introduction-11/

Related

Unit testing a started Service which has a few fields injected into it?

I am a Dagger newbie.
TL;DR:
If an Android Service has any fields injected into it using Dagger, then in order to actually perform the injection, I need to have an instance of that Service.
In Robolectric tests, this corresponds to MyService service = Robolectric.buildService(MyService.class).get(). And then, objectGraph.inject(service);
However, rest of the code that actually starts MyService still uses context.startService(context, MyService.class);.
Question: What is the idiomatic way in Dagger to address this mismatch?
Let's say I have a Service as follows:
public class MyService {
#Inject Parser parser;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String data = intent.getStringExtra("data_to_be_parsed");
parser.parse(data);
}
}
Elsewhere in my code, I have an ApiClient class that does this:
public class ApiClient{
public static void parseInBackground(Context context, String data){
//This service does not have its fields injected
context.startService(new Intent(context, MyService.class).putExtra("data_to_be_parsed", data));
}
}
That parseInBackground method will be called from an Activity in response to user interaction.
Now, I'm following TDD and hence, I haven't yet written the Application Module for this. Here's the test module:
#Module(injects = MyService.class)
public class TestModule {
#Provides #Singleton Parser provideParser(){
return new MockParser();
}
}
And finally, the test case:
#RunWith(Robolectric.class)
public class ApiTest {
#Test
public void parseInBackground_ParsesCorrectly(){
//This service has its fields injected
MyService service = Robolectric.buildService(MyService.class).get();
ObjectGraph.create(new TestModule()).inject(service);
ApiClient.parseInBackground(Robolectric.application, "<user><name>droid</name></user>");
//Asserts here
}
}
As you can see, in the test, I retrieve an instance of the service and then inject the MockParser into it. However, the ApiClient class directly starts the service using an Intent. I don't have a chance to perform the injection.
I am aware that I can have MyService perform an injection on itself:
public void onCreate(){
ObjectGraph.create(new TestModule()).inject(this);
}
But then, I am hardcoding the TestModule here.
Is there an existing idiom in Dagger to set up dependencies for such situations?
It's the wrong way to hardcode your modules either in tests or in services. Better approach is to perform creation via your custom Application object which in turn will hold singleton ObjectGraph object. For example:
// in MyService class
#Override public void onCreate() {
super.onCreate();
MyApp.from(context).inject(this);
}
// in MyApp class
public static MyApp from(Context context) {
return (MyApp) context.getApplicationContext();
}
//...
private ObjectGraph objectGraph;
#Override public void onCreate() {
// Perform Injection
objectGraph = ObjectGraph.create(getModules());
objectGraph.inject(this);
}
public void inject(Object object) {
objectGraph.inject(object);
}
protected Object[] getModules() {
// return concrete modules based on build type or any other conditions.
}
Alternatively, you can refactor last method out into separate class and make different implementations for different flavors or build types. Also you may want to set overrides=true in your TestModule's annotation.

Unable to Mock behavior using Mockito for testing Struts2 action class method

Well this is the setup that I have:
WelcomeUser.java
package org.user.www.action;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class WelcomeUser extends ActionSupport implements ModelDriven<UserPojo> {
private static final long serialVersionUID = 1L;
private UserPojo userPojo = new UserPojo();
private ApplicationDAOfactory appFactory = new ApplicationDAOfactory();
private UserPojoDao appDAOObj /*= ApplicationDAOfactory.getUserPojoDaoInstance()*/;
public WelcomeUser(){
}
public WelcomeUser(UserPojoDao appDAOObj, ApplicationDAOfactory appFactory){
this.appDAOObj = appDAOObj;
this.appFactory = appFactory;
}
public String execute(){
return SUCCESS;
}
#Override
public UserPojo getModel() {
// TODO Auto-generated method stub
return userPojo;
}
public String welcome(){
appDAOObj = appFactory.getUserPojoDaoInstance();
appDAOObj.persistUser(userPojo);
return SUCCESS;
}
}
ApplicationDAOfactory.java
package org.user.www.dao;
public class ApplicationDAOfactory {
public UserPojoDao getUserPojoDaoInstance(){
return new UserPojoDaoImpl();
}
}
WelcomeUserTest.java
package org.user.www.junit;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.StrutsJUnit4TestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.user.www.action.WelcomeUser;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.dao.UserPojoDaoImpl;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
#RunWith(MockitoJUnitRunner.class)
public class WelcomeUserTest extends StrutsJUnit4TestCase<WelcomeUser>{
#Mock private UserPojoDao appDAOObj;
#Mock private ApplicationDAOfactory appFactory;
#Mock private UserPojo userPojo;
#Before
public void setUpBeforeClass() throws Exception {
appDAOObj = mock(UserPojoDaoImpl.class);
appFactory = mock(ApplicationDAOfactory.class);
//MockitoAnnotations.initMocks(WelcomeUser.class);
new WelcomeUser(appDAOObj, appFactory);
}
#Test
public void testWelcome() throws Exception{
when(appFactory.getUserPojoDaoInstance()).thenReturn(appDAOObj);
when(appDAOObj.persistUser(userPojo)).thenReturn(userPojo);
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name" ,"user");
paramMap.put("email" ,"user#user.com");
ActionProxy proxy = getActionProxy("/submitUser");
ActionContext actionContext= proxy.getInvocation().getInvocationContext();
actionContext.setParameters(paramMap);
String result= proxy.execute();
assertEquals("success", result);
}
}
My doubt is that although I am trying to mock the behavior upon which my welcome method in the struts action class depends but it doesn't seems to be working. I have browsed through various sources but it has all gone in vain. As far as I have been able to comprehend this situation my best guess is that when I call the execute method upon the proxy instance in my test method the control does execute the welcome method as per the mapping in my struts.xml file but when execution arrives at the point where I am expecting my mocks to work it doesn't works and hits my database which I don't want. I do understand there is certainly a gap in my understanding but any help shall be appreciated. Cheers!!
I had similar issue but my case was bit different as I was using setter Injector through spring framework and my action class already had setter method for Dao.
I had to get the action from proxy and Inject mocked Dao object into my action.
I did following before executing proxy :
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
actionObj.setDaoObj(appDAOObj);
you have to figure out a way to inject mocked objects into actionObj .
Update :
Check if following works for you
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
ReflectionTestUtils.setField(actionObj, "appDAOObj", appDAOObj);
ReflectionTestUtils.setField(actionObj, "appFactory", appFactory);
String result= proxy.execute();
assertEquals("success", result);
Make sure you have spring-test-x.x.x.RELEASE.jar and spring-core-x.x.x.RELEASE.jar (Including any other dependency) in your classpath.

jUnits for backing bean with contructer

I want to write jUnit test cases for methods which are in backing bean but the problems is that bean's constructer has some calls to "facesContext" methods. calls are like this
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().
put(
BEAN_NAME,
BEAN_OBJECT
);
If I write any test case it throws "NullPointerException". I know that it is because facesContext is not initialized.
For example If I have a method like this
public String disableFields() throws ApplicationException
{
logger.info(empId);
logger.info(relationShip.getRelationshipName());
if(relationShip.getRelationshipName().equalsIgnoreCase("select"))
{
errorMessage="Please select relationship";
Utils.addMessage(errorMessage, FacesMessage.SEVERITY_ERROR);
return null;
}
showEmpName=true;// boolean value
return null;
}
kindly suggest me with code of jUnit test case if possible......
please suggest any way to write jUnits test cases for these type of methods....I am using jsf 1.2..
thanks in advance
You'll need PowerMockito's feature for mocking static methods as explained here: https://code.google.com/p/powermock/wiki/MockStatic
Here's a working example:
import org.hamcrest.core.IsEqual;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.faces.application.FacesMessage;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Utils.class)
public class AppTest {
public static final String PLEASE_SELECT_RELATIONSHIP = "Please select relationship";
#Test
public void testDisableFields() throws Exception {
PowerMockito.mockStatic(Utils.class);
Relationship relationShip = Mockito.mock(Relationship.class);
App app = new App(1, relationShip);
Mockito.when(relationShip.getRelationshipName()).thenReturn("SeLeCt");
app.disableFields();
Assert.assertThat(app.getErrorMessage(), IsEqual.equalTo(PLEASE_SELECT_RELATIONSHIP));
PowerMockito.verifyStatic(Mockito.times(1));
Utils.addMessage(PLEASE_SELECT_RELATIONSHIP, FacesMessage.SEVERITY_ERROR);
}
}

Mocking addProvider(Class<?> klass)

I am trying to get used Mockito.
I have a class
#Provider
public class SessionProvider implements InjectableProvider<Bind, Type>{
#Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
#Override
public Injectable getInjectable(ComponentContext ic, Bind bind, Type parameter) {
return new SessionInjectable();
}
}
And trying to return null when getInjectable is called.
My use case is like so
public void addProvider(Class<?> klass) {
providers.add(klass);
}
addProvider(SessionProvider.class);
How can I successfully mock SessionProvider.class?
Thanks
Edit:
My class is like so:
#Path("message")
#Produces(MediaType.APPLICATION_JSON)
public class MessageResource {
#POST
#Path("post")
public String testPostMessage(#Bind Session session, Message message) {
return "posted";
}
}
Bind annotation is using my provider. But my current framework does not accept instances of SessionProvider. It is utilizing Class instances.
By the way this is a web service. It is called by my client implementation. I would like to test my message with a mocked session. And for each request it is requested a new one. That is the reason the method is accepting Session Class instead of Session Instance.
I really started to feel that there is something wrong but at where?
Thanks
By default a mock return null :
SessionProvider sessionProvider = mock(SessionProvider.class);
assertNull(sessionProvider.getInjectable(ic, bind, parameter));
For a unit test, you can test MessageResource by invoking testPostMessage with mocks :
messageResource.testPostMessage(mock(SessionMessage.class), mock(Message.class));
or, you could create a mock SessionProvider class returning a mock Session :
#Provider
public class MockSessionProvider implements InjectableProvider<Bind, Type>{
public Injectable getInjectable(ComponentContext ic, Bind bind, Type parameter) {
return mock(Session.class);
}
}
and then register it on the framework :
addProvider(MockSessionProvider.class);

#webmethod - does not expose the method as webservice (JAX-WS)

I have a stateless session bean which is exposed as webservice. There are two methods and both have #webmethod annotation. But, only one of the method is exposed as webservice. Could anyone point out reason for this behaviour, please find the code below:
#WebService(portName = "interfaceSoapHTTPPort", serviceName = "interfaceService", targetNamespace = "http://com.demo.service/interfaceservice", endpointInterface = "com.demo.service.interfacePortType")
#SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
#Stateless(mappedName = "InterfaceBean")
public class InterfaceBean {
#PostConstruct
#PostActivate
public void initializeBean() {
}
#WebMethod
public void processPathEvent(XngEvent pathXngEvent) throws WSException {
}
#WebMethod
public void portAssignmentUpdate(WSHeader wsHeader,
PortAssignmentUpdateRequest portAssignmentUpdateRequest,
Holder<WSResponseHeader> wsResponseHeader,
Holder<PortAssignmentUpdateResponse> portAssignmentUpdateResponse)
throws WSException {
}
}
Only portAssignmentUpdate method is exposed as webservice, but not the processPathEvent method.
Thank you.
I was able to solve the problem.
We have set "endpointInterface" property in #webservice annotation. I had forgotten to added the processPathEvent() method to this interface. Hence, the method was not exposed even when #webmethod annotation is added.