JUnit and Mocks in Liferay - java

I need to make JUnit tests using Mockito or PowerMock or smth else but I don't know what to start with. I created testing folder, set mockito, but what should I do next? I couldn't find any examples so Im stucked with it. Can you show me how to write this JUnit test or at least give some idea.
public void deleteAuthor(ActionRequest actionRequest, ActionResponse actionResponse)
throws SystemException, PortalException {
long authorId = ParamUtil.getLong(actionRequest, "authorId");
AuthorLocalServiceUtil.deleteAuthor(authorId);
SessionMessages.add(actionRequest, "deleted-author");
log.info(DELETE_SUCCESS);
}
Or this:
public void addAuthor(ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException, SystemException {
String authorName=ParamUtil.getString(actionRequest,"authorName");
Author author=AuthorLocalServiceUtil.createAuthor(CounterLocalServiceUtil.increment());
author.setAuthorName(authorName);
author=AuthorLocalServiceUtil.addAuthor(author);
}
P.S. Im very newbie and made only 1 JUnit test in my life, so Im really intrested in good advice. Thanks in advance!
UPD:
I try do to smth like this:
private BookAndAuthor portlet;
#Before
public void setUp() {
portlet = new BookAndAuthor();
}
#Test
public void testDeleteBookOk() throws Exception {
PowerMockito.mockStatic(BookLocalServiceUtil.class);
long id = 1;
Book book = BookLocalServiceUtil.createBook(id);
ActionRequest actionRequest = mock(ActionRequest.class);
ActionResponse actionResponse = mock(ActionResponse.class);
when(BookLocalServiceUtil.deleteBook(book)).thenReturn(null);
Book result = BookLocalServiceUtil.deleteBook(book);
assertEquals(result, null);
}
...but with no success.

We are running JUnit test using following set-up:
i. Create test folder beside docroot in your portlet.
ii. Add unit folder to test and create your package in it.
iii. Create portal-ext.properties file in your test folder with following configuration:
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost:3309/db_name?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=your_username
jdbc.default.password=your_password
jdbc.default.automaticTestTable=C3P0TestTable
jdbc.default.idleConnectionTestPeriod=36000
jdbc.default.maxIdleTime=1200
iv. Create a suite class (say AbcSuite.java) as following:
package x.x.x;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import com.liferay.portal.util.InitUtil;
#RunWith(Suite.class)
#Suite.SuiteClasses({
// Where AxTest.class would be your test class name
A1Test.class, A2Test.class, AxTest.class
})
public class AbcSuite {
#BeforeClass
public static void setUp() throws Exception {
// Loading properties and establishing connection with database
InitUtil.initWithSpring();
System.out.println("X Portlet's Test Suite Execution : Started.");
}
#AfterClass
public static void tearDown() {
System.out.println("X Portlet's Test Suite Execution : Completed.");
}
}
v. Create a test class (say A1Test.java) as following:
package x.x.x;
import java.util.ArrayList;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class A1Test {
#BeforeClass
public static void setUp() throws Exception {
System.out.println("Test Running : A1Test");
}
#Test
public void testAddAuthor() {
Author author = AuthorLocalServiceUtil.createAuthor(
CounterLocalServiceUtil.increment());
author.setAuthorName("Testcase Author");
author = AuthorLocalServiceUtil.addAuthor(author);
Assert.assertNotNull(author);
Assert.assertTrue(author.getAuthorId() > 0);
}
}
That it! You can execute all test cases together using following command:
ant test -Dtest.class=AbcSuite*
or separately as:
ant test -Dtest.class=A1Test*

This will be an unpopular answer, but...
I have found that JUnit tests with a lot of mocking objects are not particularly useful. The balance comes in when looking at the size of the setUp() method of your test: The longer it is, the less value the test has. In the portlet world you'd have to use a lot of mocks, and you'll be more busy mirroring the runtime environment (and correcting the assumptions you made about it) than you are fixing issues that you only found during the creation of this kind of tests.
That being said, here's my prescription
Build your portlets with one thing in mind: Portlets are a UI technology. UI is inherently hard to test automatically. You're stuck between the JSR-286 standard and your business layer - two layers that probably don't lend themselves particularly well for connecting them in tests.
Keep your UI layer code so ridiculously simple, that you can go with just a bit of code review. You'll learn more from it than from humongous setUp() routines of your JUnit tests.
Factor out meaningful UI-layer code. Extract it into its own utility class or method. Test that - notice that you probably don't even need a full PortletRequest object for it, use just the actual data that it needs
Create Integration tests on top of all this. These will utilize the full stack, your application deployed in a test environment. They will provide a smoke test to see if your code is actually working. But make sure that testing correct wiring doesn't slow you down: Code of the complexity object.setStreet(request.getParameter("street")); should not be tested, rather code reviewed - and it should be either obviously right or obviously wrong.
Use proper coding standards to make reviews easier. E.g. name your input field "street" if that's the data it holds, not "input42"
With these in mind: Whenever you write a portlet with code that you believe should be tested: Extract it. Eliminate the need to mock the portlet objects or your business layer. Test the extracted code. A second { code block } within a portlet's method might be enough code smell to justify extraction to a separate class/method that can typically be tested trivially - and these tests will be totally independent of Liferay, teach you a lot about your code if they fail, and are far easier to understand than those that set up a lot of mock objects.
I'd rather err on the side of triviality of tests than on the side of too complex tests: Too complex tests will slow you down, rather than provide meaningful insight. They typically only fail because an assumption about the runtime environment was false and needs to be corrected.

Related

With JUnit 5, how to share information in `ExtensionContext.Store` between test instances?

I am running into trouble with JUnit 5 (5.0 or 5.1) and custom extension.
We are using service loader to load all implementations which then modify how our extension is bootstrapped. These implementations can be loaded just once, so I was thinking of using ExtensionContext.Store and placing it there. Every subsequent test instance would then just load it from Store instead of via service loader.
Now, I am even aware of the hierarchical context structure and I know that there is some "root" context which you can get through ExtensionContext.getRoot(). But this "root" context (instance of JupiterEngineExtensionContext) isn't really root - there is different one for every test instance.
Say you have FooTest and BarTest, then printing out getRoot() for each of them yields:
org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext#1f9e9475
org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext#6c3708b3
And hence trying to retrieve previously stored information from Store fails.
Is having this limitation intended? It makes the borderline between ClassExtensionContext and JupiterEngineExtensionContext pretty blurred.
Is there another way to globally store some information via extension?
Here is a (very) simplified version of how I tried working with the store (cutting out all other information basically). I also added some System.out.print() calls to underline what I am seeing. Executing this extension on two test classes results in what I described above:
public class MyExtension implements BeforeAllCallback {
#Override
public void beforeAll(ExtensionContext context) throws Exception {
System.out.println(context.getRoot());
if (context.getRoot().getStore(Namespace.create(MyExtension.class)).get("someIdentifier", String.class) == null) {
context.getRoot().getStore(Namespace.create(MyExtension.class)).put("someIdentifier", "SomeFooString");
} else {
// this is never executed
System.out.println("Found it, no need to store anything again!");
}
}
}
EDIT: Here is a minimal project on GH(link), run by mvn clean install, which displays the behaviour I see.
I just copied your MyExtension verbatim (i.e., with zero changes) and ran both FooTest and BarTest.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(MyExtension.class)
class FooTest {
#Test
void test() {
}
}
and
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(MyExtension.class)
class BarTest {
#Test
void test() {
}
}
And the result is:
org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext#2280cdac
org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext#2280cdac
Found it, no need to store anything again!
Thus, getRoot() works as documented.
The only explanation for why you see two different roots is that you must be executing the tests in different processes.
Please keep in mind that the root ExtensionContext instance is bound to the current execution of your test suite.
So if you run FooTest and BarTest one after the other in an IDE, that will actually result in two "test suites" with different roots. The same is true if you configure your build tool to fork between test classes.
Whereas, if you execute both test classes together in a single "test suite" (e.g., by telling your IDE to run all tests in the same package or same source tree) you will then see that there is one root like in the output I provided above.
Note, however, that there was an issue with the junit-platform-surefire-provider prior to version 1.0.3, whereby the provider launched the JUnit Platform for each test class. This would give the appearance of forking even though Surefire did not actually start a new JVM process. For details, see https://github.com/junit-team/junit5/pull/1137.

Wicket unit testing Translations.utils not found

I started recently developing in wicket and wondered how to set the wicket application in the unit test itself. I am currently using the wicket 6.8 Core.
4.1.2 for the unit test.
I am wondering how to set the Locale on the application.
Also actually creating the test application in a good way.
What i'm trying to achieve is a test to see if a set of strings can be returned which are loaded from a translation file.
//from the Class.
public Class Information(){
public Information(){}
public String getInfo(){
return TranslationUtil.getTranslation("RandomFieldNameTobeTranslated");
}
}
Unit Test:
import org.junit.Before;
import org.junit.Test;
public class InformationTest(){
#Before
public void setup() throws Exception(){
//needs to be setup in someway it can be used by the test.
tester = new WicketTester();
WebApplication web = tester.getApplication();
web.usesDeploymentConfig();
web.configure();
web.initApplication();
Session.get().setLocale(new Locale("en_us"));
}
#Test
public test(){
Information information = new Information();
assertEquals("Foo is Foo", "Foo", information.getInfo() );
}
}
The unit test will run the code and get a unable to find property.
This is just a basic test, describing the issue.
java.util.MissingResourceException:
Unable to find property: 'RandomFieldNameTobeTranslated'. Locale: null, style: null
Tried some variations with the initialization and config. But i'm too inexperienced to know how to initialize wicket on the right way for the development unit testing.
Questions:
how can I initialize wicket so it can find the locale in the session?
how to redirect wicket to the correct translation file?
The production version works, but I want to build a unit test and it seemed to require the 'application'. It can be mocked but as a last resort as this is used in allot of locations , I rather want to test 'value equals value'.
#selckin from #wicket :
Just initiate it by:
new WicketTester(new YourApplicationClas());
Actual unit test code after:
import org.junit.Before;
import org.junit.Test;
import java.util.Locale;
public class SchedulerModelTest {
#Before
public void setup() throws Exception {
new WicketTester(new ReconAdminApplication());
Session.get().setLocale(new Locale("en_us")); //always set the locale.
}
#Test
public test(){
Information information = new Information();
assertEquals("Foo is Foo", "Foo", information.getInfo() );
}
}

AndroidJUnit4.class + org.junit.Assume.assumeTrue = AssumptionViolatedException

I've managed to get my Android project transitioned over to JUnit4, and of course the main reason I wanted to do it isn't working. Would love any help if anyone's got ideas here.
The problem I'm trying to solve is that I want to automatically skip certain tests if the build is not pointed at the staging server. I've got this set up with a BUILD_TYPE which is using gradle to inject the base URL.
I set up an assumeThat clause in my setup which correctly identifies when the build is not staging, but instead of halting and ignoring the rest of the test, it throws an exception and fails.
Here's my base class for my live API tests - I've annotated descending from this with #RunWith(AndroidJUnit4.class), so in theory this should always be run with the JUnit4 runner:
package com.[my package].nonuitests.liveservertests;
import android.support.test.runner.AndroidJUnit4;
import com.[my package].nonuitests.BaseAndroidTest;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests against the live API. All tests descending from this class will
* be ignored if the BUILD_TYPE is not staging.
*/
#RunWith(AndroidJUnit4.class)
public class BaseLiveServerTests extends BaseAndroidTest {
private static final String STAGE = "staging";
/******************
* SETUP/TEARDOWN *
******************/
#Override
public void setUp() throws Exception {
super.setUp();
//TODO: Y U NO WORK?!
//This should cause the rest of the test to be skipped if it fails,
//but is instead throwing an AssumptionViolatedException.
assumeTrue(STAGE.equals(BuildConfig.BUILD_TYPE));
}
}
So, my questions:
Is there a better way to do this? In theory this could be done with flavors, but I was trying that earlier and it made everything else way more complicated.
My research indicates there's some kind of thing that Google's not implementing in their runner that's causing this to bomb out, but I'm having a hell of a time figuring out what I can/should do to fix this. Any suggestions of things I should subclass to get this to work as expected?
Any other thoughts would be most appreciated. Thanks!
Edit (1/26/15 11:40am CST): Per Grzesuav's suggestion, I took a stab at implementing this as an #Rule, but at the moment it's still not working. This seems a promising path, but it ain't working at the moment.
Edit 2 (1/26/15 12:15pm CST): OK, now it's working.
https://github.com/junit-team/junit/wiki/Assumptions-with-assume
ad 2) Custom runners could differently treat assume statement. To fix it you should write own version of Android runner and implement a way of dealing with assumes as native JUnit runner does or make a bug for android test runner.
ad 1) Suggested by me : try use JUnit Rules :
http://www.codeaffine.com/2013/11/18/a-junit-rule-to-conditionally-ignore-tests/
http://cwd.dhemery.com/2010/12/junit-rules/
OK, finally got it working with #Rules per Grzesuav's suggestion, although with significant changes since MethodRule has been deprecated. Here's a gist of what it turned out to be - I'll try to keep that updated as I refine it.
Some important notes:
You have to instantiate your #Rule in your test class, or you'll never actually hit any of your checks.
As of right now, this will not mark the test as ignored on Android, it'll just pass it without actually testing anything.
In Junit 4.12 it cannot handle tearDown
If you have tearDown you have to add an if statement with your condition rather than assumeTrue. I think the owners of Junit say it isn't supposed to work with #After
#After
override fun tearDown() {
if (junit == worksAgain()) {

Java Easymock complains with "java.lang.IllegalStateException: void method cannot return a value" or "no last call on a mock available"

We are using EasyMock for JUnit testing of our Java application inside Eclipse. Using code similar to the below, we found a strange behaviour: when running the full test suite (Eclipse Project -> Run as -> JUnit) one test case fails reproducibly. However when running it standalone it works fine.
Interface:
package de.zefiro.java.easymockexception;
public interface Fruit {
public String fall();
}
Test class:
package de.zefiro.java.easymockexception;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass;
import org.junit.Test;
public class Newton {
private static final Fruit APPLE = createNiceMock(Fruit.class);
#BeforeClass
public static void SetUpClass() {
expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
replay(APPLE);
}
#Test
public void testGravity() {
String target = APPLE.fall();
assertTrue("Missed", target.contains("HEAD"));
}
}
Test suite:
package de.zefiro.java.easymockexception;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(value = Suite.class)
#SuiteClasses( { Newton.class } )
public class ScienceTests { }
Running all tests on the Eclipse project - i.e. both ScienceTests calling Newton as well as Newton directly - produced this exception in the above small example:
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.Easymock.getControlForLastCall(EasyMock.java:175)
There is a similar question here, but it seems to be unrelated.
And in our real testing code (bigger class, but the main actors are identical to the stripped-down example) this exception:
java.lang.IllegalStateException: void method cannot return a value
at org.easymock.internal.MocksControl.andReturn(MocksControl.java:101)
I didn't find an answer either on Google nor here on StackOverflow, but found out myself now, so in the spirit of answering your own questions I'll post my findings below. Worth mentioning is also this post I found, even though it didn't help me in this particular case: EasyMock Cause-Effect Exception Mapping
Putting Breakpoints on the line initializing APPLE and inside SetUpClass() I noticed that APPLE is called exactly once, while SetUpClass is called twice. This is due to the fact that the first reference to Newton creates the class and runs the static initializers, however JUnit calls #BeforeClass for each run of the test. In this case the test is run twice: once as a normal call and once as part of the test suite.
I didn't want to change the logic (i.e. don't use static), but instead changed the static #BeforeClass to a static initialization block:
public class Newton {
[...]
static {
expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
replay(APPLE);
}
// no #BeforeClass needed anymore
[...]
}
This solved the issue in both my simplified test above and in our real test coding.
I didn't find out what the difference was that triggered the different exception message, but the findings were the same - new was called only once, #BeforeClass was called multiple times and failed on the second run. The fix also worked on both.

Choose order to execute JUnit tests

I wanted to choose the order to execute the JUnit tests.
I have 4 classes with several test methods in it, my goal is to execute, for instance, method Y of class A, then method X from class B, and finally method Z from class A.
Would you help please?
From version 4.11 you can specify execution order using annotations and ordering by method name:
import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyTest {
#Test
public void test1Create() {
System.out.println("first");
}
#Test
public void test2Update() {
System.out.println("second");
}
}
See JUnit 4.11 Release Notes
In general, you can't specify the order that separate unit tests run in (though you could specify priorities in TestNG and have a different priority for each test). However, unit tests should be able to be run in isolation, so the order of the tests should not matter. This is a bad practice. If you need the tests to be in a specific order, you should be rethinking your design. If you post specifics as to why you need the order, I'm sure we can offer suggestions.
The JUnit answer to that question is to create one test method like this:
#Test public void testAll() {
classA.y();
classB.x();
classA.z();
}
That is obviously an unsatisfying answer in certain cases (where setup and teardown matter), but the JUnit view of unit testing is that if tests are not independant, you are doing something wrong.
If the above doesn't meet your needs, have a look at TestNG.
Create a TestSuite and call the test methods in the desired order. #Yishai is right in that JUnit is designed so each test is independent. So if you are calling test methods that can be run independently then there should be no problem with creating a TestSuite to cover a scenario for a specific calling-order.
The general remark/idea that testing can be done in any arbitrary order is too strong.
It really depends on what you are testing.
For example I am testing a server where we have a changePassword action.
I think it is obvious that the order of tests is critical. After changePassword, the old password does not work anymore, and before, it does.
I don't want to revert the server state after each test, too much work. I can do it one time after all tests have been completed.
If the previous answer is not satisfying I have noticed with the Sun JVM JUnit always seems to execute unit tests in the order of which they are defined.
Obviously this is not a good idea to rely on this.
This might be interesting to you: JExample
A different approach to testing with interdepentent tests.
You can use #Order() annotation
You can do this like with #Order annotation
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyTest {
     
    #Test
    #Order(1)
    #DisplayName("First")
    public void firstTest() {
        System.out.println("a");
    }
     
    #Test
    #Order(2)
    #DisplayName("Second")   
    public void secondTest() {
        System.out.println("b");
    }
  
    #Test
    #Order(3)  
    #DisplayName("Third") 
    public void thirdTest() {
        System.out.println("c");
    }
}
Output
a
b
c

Categories

Resources