I use liferay service builder in my project and now i want to test *Util classes. It would be easy, but i don't know simple method of init environment.
For example in ant testing with spring configuration from service.xml (auto generated) i use InitUtil.initWithSpring() for init beans, but get follow error:
[junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 2,413 sec
[junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 2,413 sec
[junit]
[junit] Testcase: testJournalArticleSearch(MTest): Caused an ERROR
[junit] BeanLocator has not been set for servlet context My-portlet
[junit] com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set for servlet context My-portlet
[junit] at com.liferay.portal.kernel.bean.PortletBeanLocatorUtil.locate(PortletBeanLocatorUtil.java:42)
[junit] at com.my.service.EntityLocalServiceUtil.getService(EntityLocalServiceUtil.java:70)
[junit] at MTest.setUp(MTest.java:21)
I've seen a few articles on this problem, but it doesn't work or i don't understand these articles...
Somebody knows a simple solution to this problem?
I'm writing this as an answer - it would be more a comment, but the formatting options and length of an answer are what I'm going after.
I frequently see that people have problems writing unit tests for generated code - and *Util, together with servicebuilder, sounds like generated code (*LocalServiceUtil) to me.
My advice is to rather test your *LocalServiceImpl code and trust that the codegenerator is correct (or trust that the codegenerator tests will catch mistakes in there, but this is outside of your scope). After all, the functionality that servicebuilder's *LocalServiceUtil classes deliver is an indirection that looks up the correct implementation (based on spring configuration) and delegate to it. There's no business logic in *LocalServiceUtil classes - this is in *LocalServiceImpl classes.
The next point is: Sometimes even the *Impl-classes are hard to test, because they reach out to other services, which would need to be mocked. In this case - to keep the unit tests readable and independent of the database - I'm proposing to test a layer of code that doesn't reach out to other services. To pick on the code I stole from this answer, here's how I'd rather test it, excluding UserLocalService from the equation (caution: pseudocode, never saw a compiler, I'm editing in this input field)
The code we're about to test is:
class MyUserUtil {
public static boolean isUserFullAge(User user) {
Date birthday = user.getBirthday();
long years = (System.currentTimeMillis() - birthday.getTime()) / ((long)365*24*60*60*1000);
return years >= 18;
}
}
My Test for this would be ruling out UserLocalService:
#Test
public void testIsUserFullAge() throws Exception {
//setup (having it here for brevity of the code sample)
SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd");
Date D2000_01_01 = format.parse("2000_01_01");
Date D1990_06_30 = format.parse("1990_06_30");
User mockUserThatIsFullAge = mock(User.class);
when(mockUserThatIsFullAge.getBirthday()).thenReturn(D1990_06_30);
User mockUserThatIsNotFullAge = mock(User.class);
when(mockUserThatIsNotFullAge.getBirthday()).thenReturn(D2000_01_01);
//run
asertTrue(MyUserUtil.isUserFullAge(mockUserThatIsFullAge));
asertFalse(MyUserUtil.isUserFullAge(mockUserThatIsNotFullAge));
}
The important part here is: Your code works on a User object, not on a user Id. Thus you don't need to test the lookup. If you desperately want to test the lookup as well (e.g. test on a broader scale), call it integration test. But don't complain if it breaks often because of some unrelated changes. Because now the reasons for your test to fail are of two different sources: The lookup fails OR your implementation is incorrect. You want your UNIT test to fail for exactly one of the reasons, e.g. immediately know what went wrong when the test fails, not start debugging.
Oh, and yes, that test will start to fail in 2018, in real life I'd test more corner cases, e.g. someone who turns 18 tomorrow or did so yesterday), but this is a different topic.
I use Mockito and PowerMock for mocking the Liferay services. The PowerMock allows to mock static methods like XXXLocalServiceUtil. In the linked answer from Prakash K, you can find detailed description: Testing for custom plugin portlet: BeanLocatorException and Transaction roll-back for services testing
Related
I created a Test class:
void comp() throws IOException{
Foo foo=new Foo()
String file=readFile("xyz.txt")
Model model=foo.generate(file)
Assert.assertEquals(model.getMapA().size(),0);
Assert.assertEquals(model.getMapB().size(),0);
Assert.assertEquals(model.getListC().size(),10);
}
Is this a good approach to writing the Junit test? I mean all the asserts inside one method. An alternate approach I could think of is to have a setup method that will generate the model class and a separate method for checking the size of each attribute. The class Foo is a controller class in a spring boot application.
I am using Junit5. I also saw that Hamcrest is popular, but the last release was on Jul 09, 2012 Which raises a question should we use it or not
The main problem in your test scenario is when the first assertion fails you do not see results of next assertions, I would recommend to start using AssertJ assertions, in that case your assertions would look like (very basic example though):
Model model=foo.generate(file);
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(model.getMapA()).isEmpty();
softly.assertThat(model.getMapB()).isEmpty();
softly.assertThat(model.getListC()).hasSize(10);
});
I have written the following junit test.
#SpringBootTest
public class abc {
#Autowired
private ActorService actorService;
#Test
#Transactional
public void testCorrectIdHandlingForNewInsertedActors() {
int elementsInDb = 0;
for (Actor a : this.actorService.findAll()) {
elementsInDb++;
}
Actor actor = this.actorService.saveAndSetId(new Actor());
assertEquals(elementsInDb + 1, actor.getId());
}
}
Now I want to write some load tests for performance testing but I don't know which tools I can use within my spring application. I am using gradle as my build tool. Any tutorial will be appreciated.
PS: I have already tried zerocode but does not work for me
You have some useful features out of the box such as #RepeatedTest and #Timeout (see the JUnit 5 annotations reference here) which respectively allow you to repeat a specific test method n times and set a maximum time limit before a test will fail automatically.
Other than that, for more complete and meaningful load testing you should consider relying on a full-fledged solution such as Apache JMeter or Gatling, rather than unit tests.
I am looking for a way to start the spring context, intialize all caches and after that ask the user on the command line (cmd) what tests he want to execute.
after the tests are run the user can choose to rerun the tests or run different tests until he decide to stop the programm.
this should be based on junit as it enables us to use the same tests within different execution environments (eg. jenkins build, ...)
is there a framework that support something like this or any other adwise how to implement this?
while(true) {
userInput = parseUserInputFromConsole();
if (userWantToExit(userInput)) {
break;
} else {
JunitResult = runJunitTetsBasedOnUserInput(userInput);
generateTestRunReport(JunitResult);
}
}
additional, one test exists of more then one step, but the steps should be reusable among tests. any idea how to implement this?
You can do this by using Spring #ActiveProfiles annotation, you need to basically set which tests are applicable for which run like below:
#ContextConfiguration
#ActiveProfiles({"dev", "integration"})
public class DeveloperIntegrationTests {
// class body...
}
You can look at here
I am writing tests for a Spring Integration project, and I am running into something strange : I've read about how Spring caches the context between tests and how we can force to clean the cache with #DirtiesContext annotation. However, I'm not able to explain the behavior I observe, and it makes me think it's maybe a bug...
I have 2 different tests :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:myInterface-core.xml",
"classpath:myInterface-datasource-test.xml"})
public class PropertyConfigurerTest {
#Test
public void shouldResolvePropertyForOutPutFile(){
}
}
(it does nothing, simply loads the context, intentionnaly)
And another one, more complex with actual tests in it (skipping them in below snippet) :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:myInterface-core.xml",
"classpath:myInterface-rmi.xml",
"classpath:myInterface-datasource-test.xml"})
public class MontranMessagesFlowTest {
...
}
As you can see, these 2 tests don't load exactly the same config : second test loads one extra config file that is not required for first one.
When I run these 2 tests one after the other, second test is failing : in a nutshell, the goal of the test is to insert 2 rows in inMemory DB, start my Spring Integration flow and assert with a listener (inside a jms:listener-container) that I've received 2 JMS messages on the outbound side. I see in debug mode that actually the 2 messages don't go to same listener so I get one message instead of the 2 I expect. Somehow, the fact that I'm loading some elements of the context in first test (even if I don't do anything with them) has an impact on the second test.
I have found 2 different workarounds :
adding #DirtiesContext(classMode=ClassMode.AFTER_CLASS) on my first test.
modify the list of Spring files that I load in my first test, so that it matches exactly the one defined in the second test.
But still, I don't understand the rationale, and it looks like a bug to me.
I am using Spring Test 4.1.4.RELEASE. I've put the minimum code necessary in a separate project to be able to reproduce. I can share it if required.
Does anybody have an explanation for this ? Bug or not ?
Thanks
Vincent
#M. Deinum is correct in his comment.
For what it's worth, in Spring Integration framework tests themselves, we have started adding #DirtiesContext to all tests, to ensure any active components (such as inbound message-driven adapters) are always stopped after the tests complete.
This also has a performance/memory usage improvement for large test suites.
I have integration test (which runs under Jetty) where I open page (by using Selenium) and check that record about this activity was added to database (HSQL). But it does not work -- JPA (Hiberante) adds record (I see it in logs) but when I execute SELECT query there no records at all.
Test case:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:spring/DispatcherServletContext.xml"
})
#TransactionConfiguration(defaultRollback = false)
public class WhenUserOpenNotExistingPage
extends WhenUserAtAnyPage<NotFoundErrorPage> {
private final String currentUrl;
#Autowired
private SuspiciousActivityDao suspiciousActivities;
private String generateRandomUrl() {
return String.format(
"/tests/page-does-not-exists-%s.htm",
RandomStringUtils.randomNumeric(5)
);
}
public WhenUserOpenNotExistingPage() {
currentUrl = generateRandomUrl();
page.open(currentUrl);
}
#Test
#Transactional(readOnly = true)
public void incidentShouldBeLoggedToDatabase() {
SuspiciousActivity activity =
suspiciousActivities.findByPage(currentUrl);
assertNotNull(activity);
}
}
Also WhenUserOpenNotExistingPage() (constructorr) called twice (and I don't know why it happens and probably is the root of my problem).
Can you help me?
Thanks in advance!
I assume you are adding something to the database in the test case and the same database is being used by your application running on Jetty. If your database uses any isolation level above read uncommited, the changes you made in the test case won't be visible until that test case finishes. This is because you database code joins the transaction that was created when the test was starting.
By default this test transaction is rolled back after the test finishes, so the changes are visible within the current test (transaction), but aren't visible outside (by different threads/connections) and are rolled back. You are changing the default behaviour by using defaultRollback = false attribute, but this only means that changes you made in one test aren't visible by the web application (different database connection), but will be visible in subsequent test (after commit). Not really useful.
You have few options:
Get rid of Spring transactional test support. This means Spring won't create a new transaction every time you start a test and won't do commit/rollback. Now it is up to you when to start transaction and commit it before actually starting SElenium test.
This can easily be done by replacing #TransactionConfiguration with:
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
this will override default test execution listeners, removing TransactionalTestExecutionListener from the stack
You might run setup code from different thread or with propagation REQUIRES_NEW
Finally, you should consider doing setup outside of JUnit. Maybe you can do the setup from the application itself?
As for the constructor - new instance of JUnit test class is created per test. The authors of JUnit claim it makes the test more predictable and stateless (no dependencies between test) by cleaning up the test class prior to running every test. In practice, especially with integration tests, this is more a pain than a advantage.
By the way if you do some database manipulation in the test and commit the changes, watch out for test dependencies. The order in which tests are executed is not guaranteed in JUnit. This means that changes in one test shouldn't affect other tests.