I have a #SessionScoped bean that does some initialization at construction by calling various services (accessed via a service-locator). I would like to test if the initialized state of the bean is correct after its creation.
The bean looks something like this:
#ManagedBean
#SessionScoped
public class MyBean extends MyBeanBase {
public MyBean(){
init();
}
private void init(){
//call service-methods to initialize some fields of the bean
}
...
}
The class MyBeanBase contains a singleton-instance of a MyServiceLocator that exposes some services:
#ManagedBean(name="...")
#ApplicationScoped
public class MyServiceLocator{
#EJB
private Service1 service1;
#EJB
private Service2 service2;
...
// getters for services
}
I use the Mockito mocking framework for my unit-tests. My initial idea was to mock the services that get called in the constructor and inject these mocks into the bean instance, but this does not work, because Mockito needs an instance of the class to be able to start mocking, but the service methods get called in the constructor itself.
My second idea was to move the bean-initialization into a #PostConstruct method like this:
#ManagedBean
#SessionScoped
public class MyBean extends MyBeanBase {
private MyType field1;
...
#PostConstruct
private void init(){
//call service-methods to initialize some fields of the bean
field1 = getService1().getValue();
...
}
...
}
I read some other threads discussing this case and suggesting the use of SpringJUnit4ClassRunner and #Autowired, but I'm not 100% sure if this is the correct approach in this case.
So basically what I would like to do is use mocked services to test if the bean gets initialized correctly using those services. My questions are:
What is the best approach for this problem?
Is there a better way to design the bean so that its initialized state can be tested easily?
Does testing the state of the bean even make sense in a unit-test?
Related
While trying to write test cases for a class whose functionality deals more with boiler plate code than business logic. I started wondering if unit testing is really worth for this class. But then again, when using TDD, we are advised to write test for any piece of logic we add.
As an example the below class, just uses DI to inject dependencies and get config parameters to set up the running of the application. Other than unit testing if dependencies are correctly injected, or if destroy is called when running finishes(which would be unit testing the java CDI framework than my own code), what else I can unit test?
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
#Singleton
#Startup
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class PipsAlprConnectionRunner {
#Inject
private PipsAlprConfiguration config;
#Inject
private PipsAlprConnector connector;
#Inject
private Scheduler scheduler;
#Inject
#PipsAlprAdapterService
private ServiceStatus status;
private Timer connectorTimer = null;
#PostConstruct
public void initialized() {
status.started();
connectorTimer = scheduler.schedule(connector, 0,
1000 * config.getPollPeriodSeconds());
status.operational();
}
#PreDestroy
public void destroy() {
connectorTimer.cancel();
connector.shutdown();
status.stopped();
}
}
I was unable to think of any testing scenarios to utilize TDD, on the above class, so just came up with the code, and now i am wondering what exactly can i unit test here.
Well, a case can be made that the class does something. It changes a status, it starts a timer. You can inject mocks of these objects into the class via Mockito and then make sure, that initialized() and destroy() both do what you expect them to do to these mocks.
#RunWith(MockitoJUnitRunner.class)
public class PipsAlprConnectionRunner {
#Mock
private PipsAlprConfiguration config;
#Mock
private PipsAlprConnector connector;
#Mock
private Scheduler scheduler;
#Mock
private ServiceStatus status;
#InjectMocks
private PipsAlprConnectionRunner pipsAlprConnectionRunner ;
#Test
public void initialized_should_set_status_started() {
pipsAlprConnectionRunner.initialized();
Mockito.verify(status).started();
}
// etc.
}
It's pretty much a question of personal taste if you want to create one method per "point of failure" or one method per method/test.
Personally, I would say that the goal is 100% coverage, so even pretty simple classes that mainly delegate should be covered. What happens if someone changes anything? The test ensures that such changes will not break existing functionality.
I want to unit test a java class with an autowired final class object, as well as another autowired class that has #PostConstruct method. While it is possible to test them individually, i am not able to combine them together.
This question is an extension to the question on injecting mockito mocks into spring bean
Code to be tested
public class A {
#Autowired
private FinalClass serviceClient;
#Autowired
private ClassWithPostConstructor resourceVerifier;
//no setters or constructors
public String useBothFinalClassAndClassWithPostConstructor() {
//logic to be tested
}
}
Working Test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClass.class)
public class ATest {
//#org.mockito.Mock //fails to mock final class
#org.powermock.api.easymock.annotation.Mock
private FinalClass serviceClient;
#org.powermock.api.easymock.annotation.Mock
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
//#InjectMocks //fails since mocking final class
private A a;
#Before
public void init() {
a = new A();
//working snippet with setters created in A and without #Autowired here within the test
serviceClient = PowerMock.create(FinalClass.class);
a.setServiceClient(serviceClient);
resourceVerifier = PowerMock.create(ClassWithPostConstructor.class);
a.setClassWithPostConstructor(resourceVerifier);
}
#Test
public void testTheMethodUsingExpectAndVerify() {
//test the functionality here
EasyMock.expect(serviceClient.callService()).andReturn("someMock");
EasyMock.expect(resourceVerifier.verifyFn()).andReturn("success");
PowerMock.replayAll();
A.useBothFinalClassAndClassWithPostConstructor();
PowerMock.verifyAll();
}
}
The above code works with the need for setters in file
Expected Test class
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"file:spring-configuration/unit-testing-config.xml"})
#PrepareForTest(FinalClass.class)
public class ATest {
#Autowired
private FinalClass serviceClient;
#Autowired
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
private A a;
#Before
public void init() {
a = new A();
}
#Test
public void testTheMethodUsingExpectAndVerify() {
//test the functions here
EasyMock.expect(serviceClient.callService()).andReturn("someMock");
EasyMock.expect(resourceVerifier.verifyFn()).andReturn("success");
PowerMock.replayAll();
A.useBothFinalClassAndClassWithPostConstructor();
PowerMock.verifyAll();
}
}
//spring-configuration/unit-testing-config.xml
//same error even on customer factory
<bean id="resourceVerifier" class="org.powermock.api.easymock.PowerMock" factory-method="createMock">
<constructor-arg type="java.lang.Class" value="com.company...resourceVerifier" />
</bean>
<bean id="resourceVerifier" class="org.powermock.api.easymock.PowerMock" factory-method="createMock">
<constructor-arg type="java.lang.Class" value="com.company...serviceClient" />
</bean>
The above snippet mocks finalClass but calls #PostConstructor of ResourceVerifier.class - What should be done here to overcome this call.
Investigations
It is possible to test autowired files using #InjectMocks without the need for spring context configurations.
#InjectMock fails silently for static and final fields and when failing, it doesn't inject other mocks as well.
It is possible to mock final class using PowerMock's createMock and run the test with PowerMockRunner and #PrepareForTest. But this requires new unnecessary setters to inject the mocks for #Autowired fields.
MockitoAnnotations.#Mock doesn't work along well with PowerMock (especially when mocking final class objects) and can be solved via EasyMock.Annotations.#Mock
EasyMock and PowerMock doesn't have an #InjectMocks annotation to inject the mocks as possible by Mockito (Would have solved the problem in secs).
It is possible to inject autowired spring beans via SpringJUnit4Runner and a separate unit-testing #ContextConfiguration
It is possible to run the same test file with both PowerMockRunner and SpringJUnit4Runner with PowerMockRunnerDelegate
I know that #PostConstruct method will not be executed automatically if mocked in code than by using spring bean creation and injection.
If a wrapper factory bean class is written and used to create the mocks, it injects automatically, but calls the #PostConstruct method as well along with it.
It is not possible to depend on Springockito since it is unreliable at this stage.
But none of these worked since the usecase is a combination of all these.
Possible Solutions
Remove #Autowired fields and use Setter injections so that it is possible by mocking normally using PowerMock(Tested to work) - But it is a convention followed by external team packages - i should try my best to stick to it.
Or set #Autowired to the setters or to constructor
Alternatives?
I don't feel that the classes require reorganisation as they serve their purposes and are well designed as well.
Any other means that doesn't require to keep hands on the class under test - What if i didn't have the permissions to modify this class? i.e., a pure testing library dependent solution.
Not sure whether it is possible by PowerMockito? Haven't tried the combination of PowerMockito with PowerMock.
Hmm,
Not sure whether it is possible by PowerMockito? Haven't tried the combination of PowerMockito with PowerMock.
Seems to me you have a mess in your head and misunderstanding PowerMock/Mockito and EasyMock.
You should never use at same time PowerMockito and PowerMock, because these two classes are PowerMock friendly API for two different mocking frameworks: EasyMock and Mockito. And there is no reason to use they both.
And of course this want work
//#org.mockito.Mock //fails to mock final class
#org.powermock.api.easymock.annotation.Mock
private FinalClass serviceClient;
#org.powermock.api.easymock.annotation.Mock
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
//#InjectMocks //fails since mocking final class
private A a;
Because, you decelerate and create mocks via EasyMock API, but tries to inject it with Mockito Annotation.
You have to choose only one Mocking Framework and use suitable API for it. For now, Mockito + PowerMockito (PowerMock API for Mockito) better fit your requirements.
You may full example how it works on PowerMock github
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClass.class)
public class SpringInjectFinalClassExampleTest {
#Mock
private FinalClass finalClass;
#InjectMocks
private MyBean myBean = new MyBean();;
#Test
public void testInjectFinalClass() {
final String value = "What's up?";
when(finalClass.sayHello()).thenReturn(value);
assertEquals(value, myBean.sayHello());
}
}
I have the following RouteBuilder Class and I am using dependency injection here. How can I test this route builder? I am using JUnit and camel test classes.
public class TestRoute extends RouteBuilder {
private ServiceConfiguration serviceConfiguration;
public TestRoute(ServiceConfiguration serviceConfiguration) {
this.serviceConfiguration = serviceConfiguration;
}
#Override
public void configure() throws Exception {
String incomingURI = serviceConfiguration.getQueueConfiguration().getURI();
String outgoingURI = serviceConfiguration.getHTTPConfiguration().getURI();
from(incomingURI).
setHeader(Exchange.HTTP_METHOD, constant("PUT")).setHeader(Exchange.CONTENT_TYPE, constant("application/json")).
to(outgoingURI);
}
}
My thoughts:
Creating a testConfiguration extending ServiceConfiguration and pass that. But for that I need to set all the configuration and all because the serviceConfiguration contains many other classes. Can I use Mockito here? What is the correct and easy way to test this?
EDIT: I was using the existing route, so that I don't have to write it again. Looks like that is not the correct way of testing in camel. See my test class. Of course, its not working.
public class RabbitMQRouteTest extends CamelTestSupport {
#Mock
ServiceConfiguration serviceConfiguration;
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
System.out.println("testing");
return new TestRoute(serviceConfiguration);
}
#Test
public void testConfigure() throws Exception {
System.out.println("test");
when(serviceConfiguration.getName()).thenReturn("file://target/inbox");
template.sendBodyAndHeader("file://target/inbox", "Hello World",Exchange.FILE_NAME, "hello.txt");
Thread.sleep(1000);
File target = new File("target/outbox/hello.txt");
assertTrue("File not moved", target.exists());
}
}
As you use #Mock, MockitoAnnotations.initMocks has to be invoked. Additionally, when has also be called before passing the reference to TestRoute:
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
// Initialize serviceConfiguration
MockitoAnnotations.initMocks(this);
when(serviceConfiguration.getName()).thenReturn("file://target/inbox");
return new TestRoute(serviceConfiguration);
}
Alternatively to #Mock and MockitoAnnotations.initMocks, just use:
serviceConfiguration = org.mockito.Mockito.mock(ServiceConfiguration.class);
As when is invoked in createRouteBuilder, serviceConfiguration.getName() always returns the same result for all test methods in the JUnit test class. This could be a problem, if different test methods need different URIs.
Alternatively, you may use adviceWith instead as described here.
Camel has two ways to do the route tests, CamelSpringTestSupport and CamelTestSupport.
CamelSpringTestSupport
You can set the route with some camel-whatever-test.xml to setup the route in Spring configuration xml.
CamelTestSupport
You can set the route with RouteBuilder createRoute. And configure the endpoint with mock components.
Here is some reference link, do not forget to add the dependency jars:
http://camel.apache.org/testing.html
Using mockito makes sense in your case as you only need some small parts of the ServiceConfiguration.
On the other hand it is a bad sign that you need it for setting configuration data. You should check if your configuration can be split up into separate parts or not be used in the RouteBuilder at all. If you have one configuration structure that is used in all parts of your code you create a tight coupling between things that should be separate. If you just need the two properties queue uri and http uri in your routebuilder then consider just having two setters for them.
I'm having a hard time trying to implement unit tests on my JSF backing bean classes... For instance some of the methods use session or request parameters, obtained using this sort of code:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("paramKey");.
My question is: how can I test a method which obtains values from the session or request?
What I usually do is to avoid calling static methods into the beans I want to test. That implies your current code to be refactored:
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get("paramKey");
Are there ways to test them with their static method calls? Probably there are, but they led me to a lot of trouble more than help. So at the end I got rid of them and changed my design. Just let a second bean do it (which you'll mock later). In your case, create a #SessionScoped bean which manages that functionality:
#ManagedBean
#SessionScoped
public class SessionBean{
public Object getSessionParam(String paramKey){
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get(paramKey);
}
}
And inject that bean in every single bean that needs it (I usually extend my view/request beans from an abstract bean which has it, so don't have to implement it in every single bean):
#ManagedBean
#RequestScoped
public class RequestBean{
#ManagedProperty(value="#{sessionBean}")
private SessionBean sessionBean;
public void accessSessionParam(){
sessionBean.getSessionParam("name");
}
}
That way you can access static methods easily, via your auxiliary SessionBean. Then, how to test it? Just create a mock of it (using Mockito, for instance):
public class Test{
public void test1(){
SessionBean sb = Mockito.mock(SessionBean.class);
//Mock your 'getSessionParam' method
ValueBean vb = new ValueBean();
Mockito.when(sb.getSessionParam(Mockito.anyString()).thenReturn(vb);
//Create your bean to test and set your mock to it
RequestBean rb = new RequestBean();
rb.setSessionBean(sb);
//here you can test your RequestBean assuming
//sessionBean.getSessionParam()
//will return vb for every single call
}
}
It is possible to mock FacesContext but this is less than ideal. Mockito example:
import javax.faces.context.FacesContext;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public abstract class ContextMocker extends FacesContext {
private ContextMocker() {}
private static final Release RELEASE = new Release();
private static class Release implements Answer<Void> {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
setCurrentInstance(null);
return null;
}
}
public static FacesContext mockFacesContext() {
FacesContext context = Mockito.mock(FacesContext.class);
setCurrentInstance(context);
Mockito.doAnswer(RELEASE)
.when(context)
.release();
return context;
}
}
If your platform supports it, prefer CDI to JSF managed beans. CDI has static dependency checking and injects proxies to prevent scope leak. CDI doesn't support all of JSF's features but it is relatively easy to connect JSF managed beans to CDI where necessary.
JSF managed beans restrict the scope that you inject types into but even that can lead to scope leaks. For example, the #{sessionScope} variable can be injected into a session scope bean even though the object belongs to the request scoped ExternalContext. It is possible to overcome this by writing your own JSF bean proxies.
Note: most of this was written with Java EE 6 in mind; things might have improved with Java EE 7.
I'm looking for some design advice for a new module of the application I am working on, particularly with regards to how to make the design testable.
The problem is very common - load some data from a database, run some operations against the data, and save the result to the database. Most other modules in the application have the following pattern:
private repo; //Set in constructor
public void Run()
{
Stuff stuff = repo.LoadStuff()
Result result = RunOperationsInPrivateMethod(stuff); //private method
repo.SaveResult(result);
}
So to test this, I see that I have a couple of choices:
Inject a mock repo that I can use to return a Stuff and verify a Result.
Refactor RunOperationsInPrivateMethod to protected access, and test
the operations directly.
Am I missing any other options? What are peoples preferences?
In general, don't test private methods, instead, think whether your private method really should be a public method of another class. ie, decompose your object into smaller objects with focused functionality.
eg, perhaps Run should be
private repo; //Set in constructor
private IOperation operation; // injected in constructor or through dependency injection.
public void Run()
{
Stuff stuff = repo.LoadStuff()
Result result = operation.Run(stuff); //private instance with public method
repo.SaveResult(result);
}
then Run would be a public method of an operations class
class SecretOperation : IOperation
{
public void Run(Stuff stuff) { /* secret stuff */ }
}
Then also, you wouldn't have to load a Stuff from a database to test, just create a stuff in a fixture focused on testing SecretOperation. Now your unit tests can be more focused.