for some testing purposes it would be great not having to restart my jetty server for every test run.
With jrebel i can apply source changes directly.
Is it possible to run my jetty server in a way that i could inject changes dynamically and then rerun the tests without having to restart the server?
It depends on the kind of changes that you want to inject.
That said, I believe there is a deeper issue here. Restarting Jetty is the right thing to do from a test-quality standpoint. It ensures that each test starts from a clean page thereby minimizing the risk of inter-test dependencies. On the other hand, this is costly (time-wise) and make your suite runs slower.
If I were you, I would address this as follows: I will refactor the code that I want to test (presumably: servlets) such that they do not depend on the Jetty infrastructure, and can run stand-alone. For instance, If I have a servlet class SomeServlet with its doGet() method, I will refactor it such that it implement MyServelt whose goGet() takes a MyRequest, MyResponse parameters.
Once you do that, you can unit-test MyServlet without a Jetty server. This will allow you not only to test faster, but also ease your debugging sessions and make your components more decoupled. Of course, you will need to add some plumbing code: a class that adapts the servelt interface to a MyServelt object (via delegation).
Related
Some time ago, I implemented a remote test execution feature on JUnit 4 for the z2-environment (a Java server development and execution environment for large Java applications). Possibly similar to the Teleporter Rule of Apache Sling (for which I failed to find a JUnit 5 version).
This worked essentially like this:
A custom Runner (Z2UnitTestRunner) is declared on the test class using #RunWith
Z2UnitTestRunner passes a test invocation (actually a test description) to the remote side
On the remote side the test description is executed by a TestExecutor
A registered RunListener logs all test events back to the client side
On the client side any registered RunNotifier will be passed the test events received from the remote side
So it is rather simple actually: It just establishes a man-in-the-middle between Runner and TestExecuter. The cool thing is: While all test execution is performed in the "native" server environment of the application, tests can be triggered from the IDE or ANT/Jenkins, as if running locally. We use that quite a lot.
I am now trying to implement support for JUnit 5. I had a deeper look lately at the various extension and configuration tweaks supported by JUnit 5 but haven't really found a complete solution yet.
The most robust solution, I think, would be to integrate with the DefaultLauncher (as that is used by IDEs and ANT as far as I can tell) or via a custom launcher. The altered behavior would make sure that selectors and filters are sent to the remote side while all TestExecutionListener events would be conveyed to be client side.
Neither approach seems to be supported currently. At least, as far as I can tell, there is no way to provide a custom Launcher nor a way to change the behavior of the DefaultLauncher. But there is a LauncherFactory and a DefaultLauncher - which looks like there IS the intention to support custom launchers (are they?)!
I also looked into implementing a custom engine that would somehow take over test execution delegated to the remote side. But that seems to be the wrong level of interception. Plus I haven't found a way to "suppress" execution via the Jupiter Engine anyway.
Currently I am looking for any good idea or example that would help me move forward. Any suggestion welcome!
I want to test the effects of a library call of my program with a real device. This call starts a service, that sends an HTTP request to a server whose URL that is hard-coded in the resources.
I want to verify that the request is sent correctly. So I set up a local HTTP server, but to be able to use it I have to change/override/mock the resource so it points to http://127.0.0.1 instead.
I want to do "end-to-end" testing; in this case it's important that the service makes an actual network request, although locally.
I've tried to override the value by creating a string resource with the same name in androidTest/res/values/strings.xml, but that resource is only visible in the test package, not in the application package.
Using the Instrumentation class only allows me to obtain the Context reference, but there's no way to replace it (or the return value of getResources()) with a mock or something similar.
How can I change a resource value of an Application under test?
You have a couple choices:
Dependency injection
Stubs/mocks
SharedPreferences
Scripts or gradle tasks
Dependency injection
Use a library like RoboGuice or Dapper. Inject an object that handles making the API requests. Then, in your test setup, you can replace the injection modules with testing versions instead. That way your test code runs instead of the original; that code can pass in different strings (either hard-coded or from the test strings.xml) instead.
DI libraries can be expensive to setup: high learning curve and can be performance problems if not used correctly. Or even can introduce hard to debug problems if the scope/lifetime of the objects isn't configured correctly. If testing is the only reason to use DI, it might not be worth it to you if you're not comfortable with a DI container.
Stubs/mocks
Wrap up your calls in something that implements a custom interface you write. Your main implementation then fills in the host URL and calls the API. Then, in tests, use a combination of stubs or mocks on that interface to replace the code that fills in the host URL part.
This is less of an integration test since the stubs or mocks will be replacing parts of the code. But is simpler than setting up a dependency injection framework.
SharedPreferences
Use the Android SharedPreferences system. Have it default to a certain endpoint (production). But allow the app to be started on the testing device, then some dialog or settings to let you change the host URL. Run the tests again and now they point to a different API URL.
Scripts or gradle tasks
Write some script or gradle task to modify the source before it is compiled in certain scenarios.
This can be fairly complicated and might even be too platform or system-dependent if not done right. Will probably be fairly brittle to changes in the system. Might introduce bugs if the wrong command is run to build the final packaged version and the wrong code goes out to the market.
Personal opinion
Which do I recommend? If you and/or your team is familiar with a DI library like RoboGuice or Dapper, I recommend that option. It is the most formal, type-safe and strict solution. It also maintains more of the integrity of the stack to test the whole solution.
If you're not familiar with a good DI library, stubs/mocks and interface wrappers are a good fall back solution. They partly have to be used in the DI solution anyway, and you can write enough tests around them to cover a good majority of the cases you need to test (and are in control of). It is close enough to the DI solution that I would recommend this to everyone who doesn't use DI in the project already.
The SharedPreferences solution works great for switching between staging and production environments for QA and support. However, I wouldn't recommend it for automated tests since the app will most likely be reinstalled/reset so often during development, it would get annoying resetting that URL that often. Also, first runs of tests would probably fail; headless tests on a CI server would fail, etc. (You could default the URL to the localhost, but then you run the risk of accidentally release that default to production sometime.)
I don't recommend scripts or the hacked-up gradle tasks. Too brittle, less clear to other developers that come behind you, and more complicated then they're worth, IMO.
In addition to Jon Adams's solutions, there's a further one:
Override resource in build type
By default, a library module is built in release mode when it's used by another module. The debug mode is only used for testing (unit tests and instrumented tests). Therefore, using the resource overriding it's possible to change the resource value for the instrumentation tests for that library only, and use the original value in the library's users.
This has some caveats though:
Instrumented/integration tests must stay on the library itself, not on the main application package;
The same resource values have to be shared across all tests (unless using product flavors)
I started using dependency injection with roboguice and created an interface like DataProvider. I have an implementation which retrieves the data from some WebServer located in the WebServerDataProvider class. In Order to eliminate the waiting for the webserver i added a DummyDataProvider.
Where would i put such class? I don't like that it is in /src/main/java/my/package/providers/ since it is not real part of the application, but still i need it for development.
Typically you would use such a class in your unit tests. Roboguice works well with Robolectric , which allows you to mock things like http access. If you do that you would put your code in src/test/java/...
You could put it into the main project if you want to use it for fiddling around with the application without bothering the server each time and deactivate it with some constant for deployment, e.g.
if (DEBUG) {
setDataProvider(new MockDataProvider());
}
Proguard should be smart enough to remove this unused class if you remember to reset your variable (you might have to fiddle around with the settings there).
I am currently having issues because the WebServiceContext is not initialised, obviously because the unit test is not within the EJB container. Is there anyway to manually create a WebServiceContext for testing purposed?
I found that actually testing the EJB within a container and making it run properly across platforms and tools (e.g. code coverage) is quite difficult at best and really slow in terms of execution performance.
Rather than executing the unit test in a container, you can focus more on the business logoc side and manually inject the needed components and run the #PostConstruct manually as part of your unit test harness then test your business logic.
You can use OpenEJB for that. Take a look at this stackoverflow thread:
Test #Webservice EJBs with WebServiceContext (using OpenEJB?)
You can also unit test in GlassFish Server 3 (it's backwards compatible with Java EE 5).
I am using glassfish application server. I need to write the junits for some servlet. My question here is how can i create simulated container, mock request and response with core java libraries or i need to use some kind of tool here ?Any pointers would be helpful?
As hvgotcodes notes, it's entirely possible to write JUnit tests for servlets. But I'd advise you to think carefully before you do so.
Servlets are HTTP request listeners; they run in a servlet container, respond to any HTTP requests that come their way, and package up results to send back. That's all they should be doing, in my opinion. The real work is best left to other objects that the servlet can marshal. These can be POJOs, most likely interface-based, which will mean easier testing without having to start up a servlet container to run the test. If you decide that you need the same functionality in a non-web-based setting, it's easy to do because it already resides in objects other than a servlet.
I'd reconsider the design. Putting a lot of functionality in a servlet might be a bad decision.
1) Its not a bad idea to abstract your application logic into objects that are called by the servlet, so you can test your business logic separate from your servlet interactions.
2) Spring provides some mock classes for tests, including requests and responses. Even if you are not using Spring, you can still use those classes just for tests.
You may find Arquillian from JBoss interesting - http://community.jboss.org/wiki/Arquillian.
Test in-container!
Arquillian provides a easy mechanism to test your application code inside a remote or embedded container or by interacting as a client of the container.
Mission Statement
The mission of the Arquillian project is to provide a simple test harness that developers can use to produce a broad range of integration tests for their Java applications (most likely enterprise applications). A test case may be executed within the container, deployed alongside the code under test, or by coordinating with the container, acting as a client to the deployed code.