I'm working with the Struts2 framework and would like to unit test the execute method below:
public String execute() {
setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));
setUserPrincipal(); //fetches attribute from request and stores it in a var
setGroupValue(); //
setResults(getMyDao().getReportResults(getActionValue(), getTabName());
setFirstResultSet((List) getResults()[0]);
setSecondResultSet((List) getResults()[1]);
return SUCCESS;
}
As you can see most of the logic is database related. So how would I go about unit testing this functionality? I would like to unit test by mocking a HTTPServletRequest with few request variables inside it.
My questions are:
How can I fake/mock a request variable as if its coming from a browser
Should my unit test be calling the actual DAO and making sure that the data is coming back?
If so, how can I call the DAO from unit test since the DAO is tied to the server since jndi pool settings reside on the application server.
I'd appreciate any book/article that shows how to really accomplish this.
The code you have shown us is not enough to fully answer your question.
Line by line
setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));
This is the hardest line since it uses static method. We would need to see how ApplicationInitializer works. In ideal world the getApplicationContext() method should return mock of ApplicationContext. This mock in turns should return MyDAO when getBean("MyDAO"). mockito is perfectly capable of handling this, as well as all other mocking frameworks.
setUserPrincipal(); //fetches attribute from request and stores it in a var
Where does the request come from? Is it injected to action class? If so, simply inject mocked request object, e.g. MockHttpServletRequest.
setGroupValue(); //
Same as above? Please provide more details, what this method actually does?
setResults(getMyDao().getReportResults(getActionValue(), getTabName());
Your previously created mock should return something when getReportResults() is called with given arguments.
setFirstResultSet((List) getResults()[0]);
setSecondResultSet((List) getResults()[1]);
I guess methods below set some field on the action class. Because you have full control over what was returned from mocked getReportResults(), this is not a problem.
return SUCCESS;
You can assert whether SUCCESS was the result of execution.
Now in general
How can I fake/mock a request variable as if its coming from a browser
See above, there is a mock built-in in Spring.
Should my unit test be calling the actual DAO and making sure that the data is coming back?
If your unit test calls real DAO, it is no longer unit test. It is an integration test.
If so, how can I call the DAO from unit test since the DAO is tied to the server since jndi pool settings reside on the application server.
This means you are doing integration testing. In that case you should use in-memory database like h2 so you can still run the test on ci server. You must somehow configure your application to fetch DataSource from different place.
Final note
In essence you should inject mocks of everything to your Struts action class. You can tell mocks to return any value upon calling. Then, after calling execute(), you can verify given methods were called, fields set and result value is correct. Consider splitting this to several tests.
Code review
Struts 2 integrates perfectly with Spring. If you take advantage of that functionality Spring container will automatically inject MyDAO to your action class. The first line becomes obsolete.
This code is hard to unit test because instead of using Spring as intended (i.e. as a dependency injection framework), you use it as a factory. Dependency injection is precisely used to avoid this kind of bean lookup you're doing, which is hard to test. The DAO should be injected into your object. That way, you could inject a mock DAO when unit testing your object.
Also, this logic is not database-related at all. The DAO contains the database-related logic. This action uses the DAO, and the DAO is thus another unit (which should be tested in its own unit test). You should thus inject a mock DAO to unit test this method.
Finally, this method doesn't use HttpServletRequest (at least not directly), so I don't understand why you would need to use a fake request. You could mock the setXxx methods which use the request.
Instead of simply mocking the HTTPServletRequest, how about
mocking an actual automated targeted request to the application
itself? Check out Selenium which lets you do just that.
For testing DAOs (integration testing), you could create your databases in memory using HSQLDB, which will allow you to create / delete objects from your tests, and making sure they are persisted / retrieved properly. The advantage with HSQLDB is that your tests will run much quicker than they will with an actual database. When the time comes to commit your code, you could run the tests against your actual database. Usually, you would setup different run configurations in your IDE to facilitate this.
The easiest way to make your injected daos available to your tests is to let your unit test classes extend AbstractJUnit4SpringContextTests. You could then use the #ContextConfiguration annotation to point to multiple xml application context files, or if you use annotation based configuration, point it to your context file which has the <context:annotation-config /> declaration in it.
Related
There are many pages on the net, declaring that they describe the creation of integration tests with JerseyTest. Such as:
https://blog.codecentric.de/en/2012/05/writing-lightweight-rest-integration-tests-with-the-jersey-test-framework/
But notice! It is not an integration test really. It mocks the whole service under the API function. So, it is a unit test. And all examples for 'integration' tests that I had found, are such mocking stubs.
And I want to create a really integration test, I want to send a JSON string and get back another JSON string (or HTML). Of course, for that Jersey in coordination with JerseyTest should collaborate somehow to create a request, call my API function, follow it to the DB queries, fulfil them, and return a response that I can assert by parts.
How can I do it? (If it is possible, of course)
I have a question regarding unit test.
I am going to test a module which is an adapter to a web service. The purpose of the test is not test the web service but the adapter.
One function call the service provide is like:
class MyAdapterClass {
WebService webservice;
MyAdapterClass(WebService webservice) {
this.webservice = webservice;
}
void myBusinessLogic() {
List<VeryComplicatedClass> result = webservice.getResult();
// <business logic here>
}
}
If I want to unit test the myBusinessLogic function, the normal way is to inject an mocked version of webservice with getResult() function setup for some predefined return value.
But here my question is, the real webservice will return a list of very completed classes each with tens of properties and the list could contain hundreds or even thousands of element.
If I am going to manually setup a result using Mockito or something like that, it is a huge amount of work.
What do people normally do in this scenario? What I simply do is connect to the real web service and test again the real service. Is something good to do?
Many thanks.
You could write the code to call the real web service and then serialize the List<VeryComplicatedClass> to a file on disk and then in the setup for your mock deserialize it and have mockwebservice.getResult() return that object. That will save you manually constructing the object hierarchy.
Update: this is basically the approach which Gilbert has suggested in his comment as well.
But really.. you don't want to set up a list of very completed classes each with tens of properties and the list could contain hundreds or even thousands of element, you want to setup a mock or a stub that captures the minimum necessary to write assertions around your business logic. That way the test better communicates the details that it actually cares about. More specifically, if the business logic calls 2 or 3 methods on VeryComplicatedClass then you want the test to be explicit that those are the conditions that are required for the things that the test asserts.
One thought I had reading the comments would be to introduce a new interface which can wrap List<VeryComplicatedClass> and make myBusinessLogic use that instead.
Then it is easy (/easier) to stub or mock an implementation of your new interface rather than deal with a very complicated class that you have little control over.
I'm working with some legacy code and I need to test that some expensive service is called (it makes network calls, send emails, etc.).
I'm able to inject a fake service instead of the original one by means of the framework in use (jboss seam 2). See this question: Mock #org.jboss.seam.annotations.in behaviour for unittest
I now want my fake object to be a smarter mock to assert if it has been called or not, etc. I would like it to be a Mockito or Easymock or some other thing mock. But constructing the mock the classical way in the test and then injecting it, is not working because of the way seam 2 and seam test deals with injection. See the link above.
Question: is there a way to have my mock extend or be annotated in order to become a Mockito or something mock? How can I get a reference to it in my tests?
I disagree with the answer of the question you linked to. A unit test should test the class independantly from the environment it's supposed to work in. And dependency injection frameworks are precisely used to be able to inject mock dependencies in unit tests, without needing any complex environment to run the unit test.
I don't know Seam, but its documentation says that #In can be placed on a property accessor. I would just have the class under test like this:
public class someBean implements Serializable {
private ApplicationBean applicationBean
#In
protected void setApplicationBean(ApplicationBean applicationBean) {
this.applicationBean = applicationBean;
}
...
}
And I would just call the setter to inject the mock in the unit test.
You could also let the code as is, but provide a setter or an additional constructor to be able to inject a mock applicationBean.
You need a class with the same name but a higher precedence. I've built plenty of mocks just doing that.
You give the same #name to your mock class and you define #install(precedence=MOCK). As soon as this class is in the classpath it will be used instead of your normal class (precedence default is application if I remember correctly).
I have no code ready here just now but I mock the facesmessage for example so during testing I can read these messages from this class and validate them.
This class is simply a request dispatcher. It takes request and response objects, and pass down the work according the request type. Application logic is tested. Mocking has to be avoided. How can I write unit test for this dispatcher without turning the test into integration or system test? How are dispatchers usually tested?
EDIT: I was told to avoid mocking. I don't think I can change that decision.
There should be two parts to the code; the first is the marshalling of data between the web layer and dispatching, the second is dispatching to handlers.
Dispatching can be tested using "plain" unit testing, it's just logic to map arbitrary criteria to handlers.
The marshalling layer requires either mocking, or enough integration to create a web request and watch its routing, what's returned from its handler, etc. HtmlUnit is one solution, there are a ton of others.
Use mocks. Do the unit tests.
If you start picking and chosing which parts to test and what not to test, you might as well not test anything at all.
Then again, you might just name them "Bootstraps" or "Imposter" or some other name and get around the restrictions. Alternative, you might be able to hand-code the mocked objects and get around the restrictions that way.
I have a bean in my applicationContext-test.xml that I use for mocking an external search engine. This way, when I run tests, any time my application code refers to this search engine, I know that I am using my mock engine instead of the real one.
A problem I am facing is that I want this engine to behave differently in different scenarios. For example, when I call getDocuments(), I usually want it to return documents. But sometimes I want it to throw an exception to make sure that my application code is handling the exception appropriately.
I can achieve this by referencing the bean in my test code and changing some stubs, but then I have to change the stubs back to what they were so that my other tests will also pass. This seems like bad practice for many reasons, so I'm seeking alternatives.
One alternative I considered was to reinitialize the bean completely. The bean is initialized from the applicationContext-test.xml with a static factory method. What I want to do is:
Reference the bean from my test code to change some of its stubs
Run the test using these new stubs
At the end of this test, reinitialize the bean using the static factory method specified in applicationContext-test.xml
I tried something like this:
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContext-test.xml" });
Factory factory = appContext.getBean(Factory.class);
factory = EngineMocks.createMockEngineFactory();
But this does not do the trick. Any tests that are run after this will still fail. It seems that my new factory variable contains the Factory that I want and behaves accordingly, but when the bean is referenced elsewhere, getDocuments() still throws the exception that was stubbed in previously. Clearly, my re-initialization only affected the local variable and not the bean itself.
Can someone tell me how I can accomplish my goal?
Update
While I appreciate suggestions as to how to write better tests and better mocks, my goal is to reinitialize a bean. I believe there is value in learning how to do this whether it fits my use case or not (I believe it does fit my use case, but I'm having a hard time convincing some of my critics here).
The only answers that will get any up votes or green ticks from me are those which suggest how I can reinitialize my bean.
You should define the cases when you want a result and the cases when you want an exception. They should be differentiated by input parameters to the method. Otherwise it is not a good test. So, for a given set of parameters the output should be predictable.
How about injecting different implementations of the search engine? Just create more beans representing the different mocks of the search engine.
one test class is initialized with one mock and another test class with another mock; this, of course, means you'll have more test classes for a certain class that you are testing (not that good/clean)
or...
inject more mocks (of the search engine) in 1 testing class. some testing methods (from that testing class) use one mock, other testing methods use another mock
Instead of:
factory = EngineMocks.createMockEngineFactory();
do:
factory.callMethodThatChangesTheStateOfThisObjectSuchThatItIsSuitableForYourTest(withOptionalParameters);
Also, if you are using Spring Integration Testing, make sure to annotate your method with #DirtiesContext so it won't affect the next test.