NullPointerException when using multiple stepdefinitions in Cucumber-jvm - java

I am currently building a framework to test a Rest-API endpoint. As I am planning to write a lot of test cases, I decided to organize the project to allow me to reuse common Step Definition methods.
The structure is as follows;
FunctionalTest
com.example.steps
-- AbstractEndpointSteps.java
-- SimpleSearchSteps.java
com.example.stepdefinitions
-- CommonStepDefinition.java
-- SimpleSearchStepDefinition.java`
However when I try to call SimpleSearchSteps.java methods I get a NullPointerException
CommonStepDefinition Code
package com.example.functionaltest.features.stepdefinitions;
import net.thucydides.core.annotations.Steps;
import com.example.functionaltest.steps.AbstractEndpointSteps;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class CommonStepDefinition {
#Steps
private AbstractEndpointSteps endpointSteps;
#Given("^a base uri \"([^\"]*)\" and base path \"([^\"]*)\"$")
public void aBaseUriAndBasePath(String baseURI, String basePath) {
endpointSteps.givenBasepath(baseURI, basePath);
}
#When("^country is \"([^\"]*)\"$")
public void countryIs(String country)
{
endpointSteps.whenCountry(country);
}
#Then("^the status code is (\\d+)$")
public void theStatusCodeIs(int statusCode) {
endpointSteps.executeRequest();
endpointSteps.thenTheStatusCodeIs200(statusCode);
}
}
SimpleSearchStepDefinition.java
package com.example.functionaltest.features.stepdefinitions;
import net.thucydides.core.annotations.Steps;
import com.example.functionaltest.steps.EndpointSteps;
import cucumber.api.java.en.When;
public class SimpleSearchStepDefinition {
#Steps
private SimpleSearchSteps searchSteps;
#When("^what is \"([^\"]*)\"$")
public void whatIs(String what) {
searchSteps.whenWhatIsGiven(what);
}
}

Looks like you are missing holder class for Cucumber annotation, something like this you should have so that cucumber knows and identified that steps and features of yours:
#RunWith(Cucumber.class)
#CucumberOptions(
glue = {"com.example.functionaltest.features.steps"},
features = {"classpath:functionaltest/features"}
)
public class FunctionalTest {
}
Note that, in your src/test/resources you should have functionaltest/features folder with your .feature files according to this sample, you can ofc, change it by your design

Can you take a look at Karate it is exactly what you are trying to build ! Since you are used to Cucumber, here are a few things that Karate provides as enhancements (being based on Cucumber-JVM)
built-in step-definitions, no need to write Java code
re-use *.feature files and call them from other scripts
dynamic data-driven testing
parallel-execution of tests
ability to run some routines only once per feature
Disclaimer: I am the dev.

I solved this issue by using a static instance of RequestSpecBuilder in the AbstractEndpointSteps instead of RequestSpecification.
Therefore, I was able to avoid duplication of StepDefinitions and NPE issues altogether

Related

JOOQ is not generating classes

I have a problem with JOOQ framework (3.13.4) along with Spring Boot and Java 8.
The problem is that I'm trying to generate domain classes using java code way (instead of using codegen plugin with maven which had some troubles with custom naming strategy provider). So as first let me show You the #Configuration class which contains (at least I believe that it contains) all of the necessary beans:
import com.ormtester.common.base.Measurer;
import com.ormtester.common.utils.enums.OrmType;
import com.ormtester.datasources.config.RouteableDataSource;
import org.jooq.SQLDialect;
import org.jooq.codegen.GenerationTool;
import org.jooq.impl.DataSourceConnectionProvider;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultDSLContext;
import org.jooq.impl.DefaultExecuteListenerProvider;
import org.jooq.util.xml.jaxb.Schema;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.jooq.meta.jaxb.*;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.PostConstruct;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
public class JooqConfigurator {
private Properties moduleProperties;
private RouteableDataSource routeableDataSource;
public JooqConfigurator(RouteableDataSource routeableDataSource) {
this.routeableDataSource = routeableDataSource;
try {
moduleProperties = new Properties();
moduleProperties.load(JooqConfigurator.class.getClassLoader()
.getResourceAsStream("jooq.properties"));
} catch (Exception ignore) {}
}
#Bean
public DataSourceConnectionProvider connectionProvider() {
return new DataSourceConnectionProvider(routeableDataSource);
}
#Bean
public ExceptionTranslator exceptionTransformer() {
return new ExceptionTranslator();
}
#Bean
public DefaultConfiguration configuration() {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(connectionProvider());
jooqConfiguration.set(new DefaultExecuteListenerProvider(exceptionTransformer()));
jooqConfiguration.set(SQLDialect.DEFAULT);
return jooqConfiguration;
}
#Bean
public DefaultDSLContext dsl() {
return new DefaultDSLContext(configuration());
}
#PostConstruct
public void generateCode() {
try {
GenerationTool.generate(new org.jooq.meta.jaxb.Configuration()
.withJdbc(new Jdbc()
.withDriver("com.mysql.cj.jdbc.Driver")
.withUrl("jdbc:mysql://localhost:3306/ormtester?useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC")
.withUser("root")
.withPassword("root123"))
.withGenerator(new Generator()
.withName("org.jooq.codegen.JavaGenerator")
.withStrategy(new CustomStrategyProvider())
.withDatabase(new Database()
.withName("org.jooq.meta.mysql.MySQLDatabase")
.withIncludes(".*")
.withExcludes("")
.withSchemata(new SchemaMappingType().withInputSchema("ormtester").withOutputSchema("ormtester"))
.withInputCatalog("ormtester")
.withOutputCatalog("ormtester"))
.withTarget(new Target()
.withPackageName("com.ormtester.jooq.domain")
.withDirectory("jooq/src/main/java"))));
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
}
RouteableDataSource is a type that extends AbstractRoutingDataSource because in this case I need to have a possibility to change datasource at runtime. This thing is working well in the other regions of the project (or in another words with tools like Hibernate or MyBatis).
As You can see there is a #PostConstruct method which is used for generating domain classes and the problem is that this method doesn't generate any error or something but the classes are also not generated. I've tried to run it using PostgreSQL and Oracle database (of course changing the driver, database name etc.) and the situation is looking exactly the same.
One interesting thing is that when I'm running this code and package com.ormtester.jooq.domain is present - during the method execution domain package is getting removed.
I'd also like to mention that JOOQ autoconfiguration is disabled by excluding JooqAutoConfiguration class through the #SpringBootApplication annotation located at the project's main (starter) class.
IDE is running in administrator's mode and - what can be also interesting - if I will set the breakpoint in the getJavaClassName() method in my custom naming strategy provided (CustomStrategyProvider which extends DefaultGeneratorStrategy class, the breakpoint is reached everytime this method is used.
So does anyone faced the same problem and/or simply can tell me if I'm doing something wrong or something is missing in the code snippet that I've provieded here? I have this problem since about 4 days and now I'm running out of the ideas what can be wrong. I went through the tons of topics on many forums and nothing helped me, including the tutorials on the author's page (which in my opinion simply lacks of important informations).
I'll be really grateful for every help - thanks in advance!
Code generation is a build task, not a runtime task. I can't think of a reasonable scenario where generating code only at runtime would make sense.
The problem is that I'm trying to generate domain classes using java code way (instead of using codegen plugin with maven which had some troubles with custom naming strategy provider)
You have to create a separate maven module (or project) where you build the custom naming strategy, and then add that as a dependency to the jOOQ code generation plugin. This works the same way as with the JPADatabase, where entities have to be placed in a separate maven module.

Java Junit4 Supporting extended base class

a question:
When I do something like:
package path.to.common.package.test;
#BeforeClass
public class CommonTestSetup {
public void setUp() {
// Setup Stiff
}
}
And the other class setup in the same package:
package path.to.common.package.test;
public class TestTest extends CommonTestSetup {
#Test
public void testGetTestReturnsCorrectStrings() {
// do asserts etc
}
}
And then executing JUnit test on testGetTestReturnsCorrectStrings I am getting an error:
org.junit.runners.model.InvalidTestClassError: Invalid test class 'org.junit.runner.manipulation.Filter':
1. No runnable methods
at org.junit.runners.ParentRunner.validate(ParentRunner.java:456)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:99)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:84)
at org.junit.runners.JUnit4.<init>(JUnit4.java:23)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:66)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:66)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:39)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:80)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:71)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:46)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:523)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)
Why is that? Does it mean JUnit 4 does not support Test classes extending a base class?
The idea behind this was to create a single SetUp base class, shared by many other test classes that need it.
Originally I even tried to have the base class in another package entirely, then moved it to the same package for testing, and got a different error (the one above).
use import org.junit.Test;
instead of import org.junit.jupiter.api.Test;
Based on the JUnit documentation:
Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class
So move the #BeforeClass annotation to the setUp method and make into a static method.
You may also check for things like
class classname {
class another class{
}
}
Keep one class in file it helps
I experienced similar ... I hopes it help someone ;-)

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() );
}
}

JUnit and Mocks in Liferay

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.

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.

Categories

Resources