Java test the UI using Mockito - java

I am writing some unit tests for an UI implementation. The problem that I came across is that I can't add a certain component to a container.
A quick example:
I have declared a JComboBox myComboBox.
The problem is when I call myComboBox.getParent() I get a null value.
This causes further problems and my tests fail.
I have to specify that I'm using Mockito for testing and that the combo box was declared with the #Mock annotation before. My assumption is that because I use mocked objects I get this error.
So the question is: Does anyone have any ideas how to add my mocked component to a parent container, so that it won't be null? Or should I change the mocking framework and use JMock?

Testing the UI is no easy job. As the Documentation states, all components must be accessed on the Event Dispatching Thread.
Frameworks like assertj may be a help.

Related

How is if condition different from JUnit's assumingThat?

Why would one use JUnit's assumingThat() method instead of a plain old simple if clause? If one can use simple thing why would you complicate it with something else that does it the same way.
Is it just a expressionality thing, or what's the advantage, I don't see other benefits.
Junit's assume is not a new feature in version 5, it has been there since v4.4 and it has other applications.
You could skip testing with if, but with assume you can tag failure lifecycle method to it, using a Listener.
Example Situation (Most Common) - You could have a listener, which creates reports of the test. And there could be a code to add the failed tests, passed tests and assume failed tests to the report. If you want to achieve this without using listener or testAssumptionFailure method, then you would have to repeatedly call it everywhere.
Instead adding a listener makes it modular and maintainable.
You have many varities of assume methods which you could use to stop repeatedly write if, else and messages.

TestNG - #BeforeMethod for specific methods

I'm using Spring Test with TestNG to test our DAOs, and I wanted to run a specific text fixture script before certain methods, allowing the modifications to be rolled back after every method so that the tests are free to do anything with the fixture data.
Initially I thought that 'groups' would be fit for it, but I already realized they're not intended for that (see this question: TestNG BeforeMethod with groups ).
Is there any way to configure a #BeforeMethod method to run only before specific #Tests? The only ways I see are workarounds:
Define an ordinary setup method and call at the beginning of every #Test method;
Move the #BeforeMethod method to a new class (top level or inner class), along with all methods that depend on it.
Neither is ideal, I'd like to keep my tests naturally grouped and clean, not split due to lack of alternatives.
You could add a parameter your #BeforeMethod with the type 'java.lang.reflect.Method'. TestNG will then inject the reflection information for the current test method including the method name, which you could use for switching.
If you add another 'Object' parameter, you will also get the invocation parameters of the test method.
You'all find all on possible parameters for TestNG-annotated methods in chapter 5.18.1 of the TestNG documentation.
Tests are simply not designed to do this. Technically speaking, a single tests is supposed to handle being idempotent for itself meaning it sets up, tests, and takes down. That is a single test. However, a lot of tests sometimes have the same set-up and take down method, whereas other tests need one set-up before they all run. This is the purpose of the #Before type tags.
If you don't like set-up and tear-down inside your test, your more then welcome to architect your own system, but technically speaking, if certain methods require specific set-ups or tear-downs, then that really should be embodied IN the test, since it is a requirement for test to pass. It is ok to call a set-up method, but ultimately, it should be OBVIOUS that a test needs a specific set-up in order to pass. After all, if your using specific set-ups, aren’t you actually testing states rather than code?

How can I unit test this method in java?

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.

How to re-initialize my bean

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.

Using normal mock and NiceMock within the same mockControl

Is it possible to use a niceMock and a "normal" mock within the same mockControl object?
Currently if I try to set one of the mock to nice
someMock = mockControl.createMock(someClass.class);
EasyMock.resetToNice(someMock);
It seems to reset the entire control to nice
So i would like a way to have different mock type in the same control.
Thank you
It is not possible. However, you can always record method calls asStub to have a nice behavior on a default mock.

Categories

Resources