I'm trying to write some unit tests for a gwt-dispatch service with JUnit. I'm getting the following error when stepping through the test with my debugger:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
I'm going to simplify the code a bit here -- hopefully I'm not stripping out anything necessary.
import junit.framework.TestCase;
import net.customware.gwt.dispatch.client.standard.StandardDispatchService;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
...
public class LoggedInServiceTest extends TestCase {
Injector i;
StandardDispatchService service;
protected com.google.inject.Injector getInjector() {
return Guice.createInjector(new ServletModule(),
new TestServletModule(),
new ActionsHandlerModule(),
new TestDispatchModule(),
new OpenIdGuiceModule());
}
public void setUp() throws Exception {
i = getInjector();
service = i.getInstance(StandardDispatchService.class);
}
public void testNotLoggedIn() {
try {
GetProjectsResult result = (GetProjectsResult) service.execute(new GetProjectsAction());
result.getSizeOfResult();
} catch (Exception e) {
fail();
}
}
}
The service request is indeed supposed to be going through a GuiceFilter, and it looks like that filter is not being set.
Any ideas on what other setup needs to be done to register the filter?
The problem is just what it states. You are trying to access a scoped object, but you are not currently in the scope. Most likely, your test is asking the injector for a RequestScoped object or an object that has a RequestScoped object in the injection dependency tree, but the test didn't do anything to enter the scope.
Binding the GuiceFilter in the test doesn't help, because your test isn't trying to send an HttpServletRequest through GuiceFilter to a servlet.
The best option would be to unit test your code. Create your classes in isolation, injecting mocks.
Assuming you want to do some kind of integration test, you have three options:
Have your test install a test module that called bindScope(RequestScoped.class, new FakeScope). The FakeScope class would implement Scope and have methods to enter and exit the scope. You may have to "seed" the scope with fake implementations of objects you depend on. See the Guice CustomScopes wiki page. This is the best option for integration tests, IMHO
Use ServletScopes.scopeRequest (Javadoc) to run part of the test code inside of a simulated request scope. This gets a bit ugly since you need to pass a Callable.
Do a full end-to-end test. Start your server and send it requests using Selenium. It's really hard to get good coverage this way, so I would leave this to things that you really need a browser to test.
Things might get a bit messy if the class you are testing depends indirectly on HttpServletRequest or HttpServletResponse. These classes can be challenging to setup correctly. Most of your classes should not depend on the servlet classes directly or indirectly. If that is not the case, you are either doing something wrong or you need to find a good action framework that allows you have most of your code not depend on these classes.
Here's an example of approach 1, using SimpleScope from the Guice CustomScopes wiki page:
public class LoggedInServiceTest extends TestCase {
private final Provider<StandardDispatchService> serviceProvider;
private final SimpleScope fakeRequestScope = new SimpleScope();
private final HttpServletRequest request = new FakeHttpServletRequest();
protected Injector createInjector() {
return Guice.createInjector(new FakeRequestScopeModule(),
new LoggedInServiceModule();
}
#Override
protected void setUp() throws Exception {
super.setUp();
Injector injector = createInjector();
scope.enter();
serviceProvider = injector.getProvider(StandardDispatchService.class);
}
#Override
protected void tearDown() throws Exception {
fakeRequestScope.exit()
super.tearDown();
}
public void testNotLoggedIn() {
fakeRequestScope.enter();
// fill in values of request
fakeRequestScope.seed(FakeHttpServletRequest.class, request);
StandardDispatchService service = serviceProvider.get();
GetProjectsAction action = new GetProjectsAction();
try {
service.execute(action);
fail();
} catch (NotLoggedInException expected) {
}
}
private class FakeRequestScopeModule extends AbstractModule() {
#Override
protected void configure() {
bind(RequestScoped.class, fakeRequestScope);
bind(HttpServletRequest.class)
.to(FakeHttpServletRequest.class)
.in(RequestScoped.class)
}
}
}
Write an AppSession interface and two implementations: HttpAppSession and MockAppSession.
Make your server-side handlers depend on AppSession and not on HttpSession directly.
Use Guice to inject HttpSession into HttpAppSession. That's the one you'll use in production, and for actually running your app. within a real servlet container.
The MockAppSession should not depend on HttpSession, nor HttpServletRequest, nor any other Guice Http scope. That's the one you'll use during testing.
Now, your Guice module should inject an AppSession implementation as follows:
bind(AppSession.class).to(MockAppSession.class)
bind(MockAppSession.class).in(Singleton.class)
That'll sort you out.
Related
I'm writing a Dropwizard application and using Feign for building client calls to outside services. I have custom encoders and decoders I'm registering with the feign.Builder like so:
this.feignBuilder = Feign.builder()
.contract(new JAXRSContract()) // we want JAX-RS annotations
.encoder(new JacksonEncoder()) // same as what dropwizard is using
.decoder(new CustomDecoder())
.errorDecoder(new CustomErrorDecoder())
.requestInterceptor(new AuthKeyInterceptor(config.getInterceptor()));
I'm writing unit tests for the feign client calls so I can watch how the feign machinery deals with my encoder/decoder overrides and bubbles on exceptions. I'm not interested in writing integration tests with a fake server right now (this is the most common type of test i see people writing for this situation).
This should be straight forward. I want to mock the point at which feign makes the request and have it return my fake response. That means I should mock the call to feign.Client.Default.execute so it returns my fake response when it makes the request a this call site. An example of what that mock looks like:
String responseMessage = "{\"error\":\"bad\",\"desc\":\"blah\"}";
feign.Response feignResponse = FeignFakeResponseHelper.createFakeResponse(404,"Bad Request",responseMessage);
Client.Default mockFeignClient = mock(Client.Default.class);
try {
when(mockFeignClient.execute(any(feign.Request.class),any(Request.Options.class))).thenReturn(feignResponse);
} catch (IOException e) {
assertThat(true).isFalse(); // fail nicely
}
No luck. The Cleint.Default class isn't mocked when I reach the call site for the request in the code. What am I doing wrong?
As mentioned before, Mockito is not powerful enough.
I solved this with a manual mock.
It's easier than it sounds:
MyService.Java
public class MyService{
//My service stuff
private MyFeignClient myFeignClient;
#Inject //this will work only with constructor injection
public MyService(MyFeignClient myFeignClient){
this.MyFeignClient = myFeignClient
}
public void myMethod(){
myFeignClient.remoteMethod(); // We want to mock this method
}
}
MyFeignClient.Java
#FeignClient("target-service")
public interface MyFeignClient{
#RequestMapping(value = "/test" method = RequestMethod.GET)
public void remotemethod();
}
If you want to test the code above while mocking the feignclient, do this:
MyFeignClientMock.java
#Component
public class MyFeignClientMock implements MyFeignClient {
public void remoteMethod(){
System.out.println("Mocked remoteMethod() succesfuly");
}
}
MyServiceTest.java
#RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
private MyService myService;
#Inject
private MyFeignClientMock myFeignClientMock;
#Before
public void setUp(){
this.myService = new MyService(myFeignClientMock); //inject the mock
}
//Do tests normally here...
}
It turns out Mockito is not powerful enough to do the thing I assumed it could do. The correct solution is to use PowerMockito to mock the constructor so Client.Default returns the mocked instance when it is instantiated in the class that holds that reference.
After a lot of compilation-error pain I got PowerMockito to compile and it seemed like it was going to work. Alas it failed to return my mock and the calls were still going through. I've tried PowerMockito in the past and never got around to using it because of the extra problems it caused. So I'm still of the opinion that it's not super easy to just plug and play.
It's a shame that trying to do something like this is so hard.
I have a Jersey endpoint which uses a custom OSGi Service ExceptionManager Service.
#Path("service")
public class ServiceFacade {
private volatile ExceptionManager exceptionManager;
public ServiceFacade() {
BundleContext bC = FrameworkUtil.getBundle(ServiceFacade.class).getBundleContext();
ServiceReference<ExceptionManager> sR = bC.getServiceReference(ExceptionManager.class);
if (sR != null)
this.exceptionManager = bC.getService(sR);
}
#GET
#Consumes({MediaType.APPLICATION_JSON})
#Produces(MediaType.APPLICATION_JSON)
public Response sayHello() {
try {
if (exceptionManager == null)
return Response.status(Status.SERVICE_UNAVAILABLE).build();
// Do some work...
} catch (Exception e) {
exceptionManager.handle(e);
}
}
}
This Jersey class is added to the Jersey Application as a simple class, that means that every time a user hits this endpoint, a new instance of this class is created to handle the request. As you can see, the class contains a constructor which initializes the ExceptionManager Service. My question is, isn't there a simplified way of retrieving the service without going to BundleContext?
I have seen DependencyManager, but this bundle seems to only add the dependencies to the class (ServiceFacade in this case) during the Activation process, but that dependency resolution is too early this has to be done during run-time, every time an instance is created. Bellow is an approximation with DependencyManager but is not a solution for this:
public class Activator extends DependencyActivatorBase {
#Override
public void init(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception {
dependencyManager.add(createComponent()
.setImplementation(ServiceFacade.class)
.add(createServiceDependency()
.setService(ExceptionManager.class)
.setRequired(true));
}
}
Thanks.-
You can obtain the reference to an OSGi service without accessing to BundleContext by using Declarative Services. A tutorial can be found here.
You can make the endpoint a singleton resource. This way you can let the dependency manager create a single instance and inject services and then add that instance to the Jersey application.
There are a few limitations, like Jersey's field or constructor injection does not work. You also have to be careful about concurrency when using fields of the resource.
This is my mock code for testing end to end:
#RunWith(MockitoJUnitRunner.class)
public class testRest extends Jersey Test{
DAOFactory mockDAOfactory;
RPRestrictionReasonDAO fakeDao;
#Before
public void init() {
mockDAOfactory = mock(DAOFactory.class);
fakeDao = mock(RPRestrictionReasonDAO.class);
}
#Test
public void testServiceWorks() throws Exception {
//Assuming I hav already initialized restrictReasons with a dummy value
when(fakeDao.findAll()).thenReturn(restrictReasons);
when(mockDAOfactory.getRPRestrictionReasonDAO()).thenReturn(fakeDao);
String response = client().resource("http://localhost:9998/")
.path("EmployerDetails/PossibleRestrictions")
.get(String.class);
System.out.println("Response is " + response.toString());
}
}
Whenever I do this, I always get the ACTUAL results in my DB rather than the restrictReasons. I've tried all blogs but nothing seems to help. How I get around this? lemme know If I need to post more code.
Note: I have implemented the methods while extending Jersey Test with Grizzly container.
From what I can tell from your code, you are creating the mocks but not actually using the mocks in your client / server implementation.
For a mock to work, it needs to be used by the underlying implementation, not just created in your test class. In this case, assuming your test is running in the same JVM as the server you are testing against, you need to inject your created mocks into the classes that rely on them.
The other answer by #inkalimeva is attempting to address this issue for you by injecting the mocks into your DAO factory. You may be able to fix the error you are experiencing with that answer by changing the DAOFactory declaration to be the concrete class used instead of the abstract one.
E.g.
#InjectMocks
DAOFactoryImpl mockFactory;
Assuming DAOFactoryImpl is your concrete factory class.
Try this, with injecion of mocks using annotations.
#RunWith(MockitoJUnitRunner.class)
public class testRest extends Jersey Test {
#InjectMocks
DAOFactory mockDAOfactory;
#Mock
RPRestrictionReasonDAO fakeDao;
#Before
public void init()
//Do nothing
//mockDAOfactory = mock(DAOFactory.class);
//fakeDao = mock(RPRestrictionReasonDAO.class);
}
#Test
public void testServiceWorks() throws Exception {
//Assuming I hav already initialized restrictReasons with a dummy value
when(fakeDao.findAll()).thenReturn(restrictReasons);
when(mockDAOfactory.getRPRestrictionReasonDAO()).thenReturn(fakeDao);
String response = client().resource("http://localhost:9998/")
.path("EmployerDetails/PossibleRestrictions")
.get(String.class);
System.out.println("Response is " + response.toString());
}
}
Is anyone aware of any examples of testing a Java based Play Framework controller by setting mock objects?
I am using Spring in my Play project so all my controller methods are not static.
Testing the tradional way, Play shows my controller as having static methods and I just cant see a way of how I can inject mocks into my object
Result result = callAction(
controllers.routes.ref.LoginController.authenticate(),
fakeRequest().withFormUrlEncodedBody(TestUtils.SUCCESSFUL_LOGIN_MAP)
);
I have a number of services that need to be called in the LoginController and I would like to set those up as mocks
Any help is greatly appreciated
Thanks
Damien
I was looking for the solution of the same problem. So far the best result I was able to achieve is this:
public class MyObjectControllerTest{
private final MyObjectDAO dao = mock(MyObjectDAO.class);
private final MyObjectController controller = new MyObjectController(dao);
public static FakeApplication fakeApplication;
#BeforeClass
public static void startApp() {
fakeApplication = Helpers.fakeApplication();
Helpers.start(fakeApplication);
}
#AfterClass
public static void stopApp() {
Helpers.stop(fakeApplication);
}
#Test(expected = NotFoundException.class)
public void testFailWithUnknownMyObjectKey() throws Throwable {
when(dao.getByKey(any(UUID.class), any(UUID.class), any(Boolean.class))).thenReturn(null);
controller.get(CassandraUUIDs.timeBased());
}
#Test
public void testGetSuccess(){
MyObject deletedObject = MyObjectTestGenerator.generateMyObject();
deletedObject.setDeleted(true);
when(dao.getByKey(any(UUID.class), any(UUID.class), any(Boolean.class))).thenReturn(deletedObject);
try {
Result result = controller.get(CassandraUUIDs.timeBased());
assertThat(status(result)).isEqualTo(Http.Status.GONE);
assertThat(contentType(result)).isEqualTo(Http.MimeTypes.JSON);
assertThat(contentAsString(result)).isEqualTo(ErrorMsg.OBJECT_DELETED.toJson().toString());
} catch (MyObjectsException e) {
e.printStackTrace();
fail("Failed to send MyObject.get request.");
}
}
}
What I do here is instantiate an instance of the controller class and pass mocked DAO instance. Please note that I don't use static controller methods in my code as well.
One issue with this workaround I found so far is that Action (I have custom one) is not working. But Action can (and probably must) be tested separately.
I'm trying to create an EJB factory class, which works like this: You have a method which takes as argument a class of an EJB, then it checks whether the EJB has a remote interface (if not throw an exception) and if it does, it returns the concerning EJB.
The code below does exactly this. However the object it returns is of the type of the remote interface of the concerning bean and not of the bean itself. How can I change this? Is there a way to tell Java that the generic type T is of the same type as the class passed to the methods.
import java.util.Properties;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.naming.*;
public class EJBFactory
{
private InitialContext ctx;
public EJBFactory() throws NamingException {
ctx = new InitialContext();
}
public EJBFactory(String host, String port) throws NamingException {
Properties props = new Properties();
props.setProperty("org.omg.CORBA.ORBInitialHost", host);
props.setProperty("org.omg.CORBA.ORBInitialPort", port);
ctx = new InitialContext(props);
}
.
// To improve: The object returned should be of the type ejbClass
// instead of the remote interface, which it implements
public <T> T createEJB(Class ejbClass) throws NamingException
{
Class remoteInterface = null;
for(Class interface_: ejbClass.getInterfaces()) {
if(interface_.isAnnotationPresent(Remote.class))
remoteInterface = interface_;
}
if(remoteInterface == null)
throw new IllegalArgumentException(
"EJB Requires a remote interface");
// Get the stateless annotation, then get the jndiName
Stateless stateless =
(Stateless)ejbClass.getAnnotation(Stateless.class);
String jndiName = stateless.mappedName();
T ejbObj = (T) ctx.lookup(jndiName);
return ejbObj;
}
}
Example of a unit test which uses the Factory.
import junit.framework.TestCase;
public class SimpleEJBTest extends TestCase
{
TestRemote testBean;
#Override
protected void setUp() throws Exception {
super.setUp();
EJBFactory ejbFactory = new EJBFactory();
testBean = ejbFactory.createEJB(TestBean.class);
}
public void testSayHello() {
assertEquals("Hello", testBean.sayHello());
}
}
Note: The example works with Glassfish, I didn't test it with any other app server.
Clients of EJBs interact with them through the local/ remote interface that the EJBs implement. Client applications never have direct access to an actual session bean class instance. This is done to make instance pooling possible, where the container can reuse EJB instances to service different requests.
I'm not sure why you need to access the actual bean's object (since obviously I dont know your requirement). But if you still need to create an instance of that you can do it as follows using reflection Class.forName(className).newInstance(); Again the instance that you create like this is not an EJB. It is just a POJO thats all.
EDIT - after your comment regarding junit testing: When you access business methods from a JavaSE as follows, you are actually calling the methods in the EJB - just that you interact thru the interface. So if you want to test any business methods you can still do it from an object got thru a JNDI lookup in a Junit test.
//MyGreatBean implements MyGreat. MyGreat has #Remote, MyGreatBean has #Stateless
ref = jndiContext.lookup("MyGreatBean/remote");
MyGreat bean = (MyGreat) ref;
String retValue = bean.businessMethod();
assertEquals("Success", retValue);
From an earlier comment, I get a feeling you want to check what kind of annotations have been added to the actual EJB class - if you want to do that kind of checking without actually running the business methods, you can create an instance using Class.forName... like I mentioned above. When you create an instance like this you can only call methods that don't do any "Java EE" stuff. For example you can call a method in the EJB class that is as follows
public String someMethod(){
return "I am a POJO but I look like an EJB";
}
I do not think that you can get the EJB object. You can only get the interface. The createEJB should be called with the interface and it returns the interface.
try replacing
public <T> T createEJB(Class ejbClass) throws NamingException
with
public <T> T createEJB(Class<T> ejbClass) throws NamingException
Can you try this?
Create a interface. Make it have #Remote. Your ejb that is annotated with #Stateless should implement the above created interface. Now try to do the same thing that you are doing I think it should give you the desired result. Typing it down here without copying from an ide so excuse any errors. But you should get the drift I guess.
#Remote
public interface Example{
String some();
}
#stateless
public class ExampleBean implements Example{
}