For a JavaEE project with working JUnit 5 tests I decided to give ActiveJDBC a try. Unfortunately I implemented all the tests with JUnit 5 before this decision so I have to update my tests for the usage with ActiveJDBC and was wondering why they won't get the test-db connection out of the database.properties file when extending the class with 'DBSpec' and just throw an DBException when using JUnit version 5 instead of version 4:
org.javalite.activejdbc.DBException: Failed to retrieve metadata from DB, connection: 'default' is not available
JUnit 5 - test
import org.javalite.activejdbc.test.DBSpec;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
#RunWith(JUnitPlatform.class)
public class MyModelTest extends DBSpec {
//Test will fail with DBException
#Test
public void one() {
MyModel model = new MyModel();
a(model).shouldBe("valid");
}
}
JUnit 5 - dependencies
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
When i switch to JUnit 4, everything works as expected
JUnit 4 - test
import org.javalite.activejdbc.test.DBSpec;
import org.junit.Test;
public class MyModelTest extends DBSpec {
//Test will pass
#Test
public void one() {
MyModel model= new MyModel();
a(model).shouldBe("valid");
}
}
JUnit 4 - dependencies
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
It won't be that much of a deal to just 'rewrite' my tests for JUnit4 but are there any plans to support JUnit5 in the near future?
You are correct, JUnit5 is not supported yet. We filed a new issue: https://github.com/javalite/activejdbc/issues/784 to add support for it. Please, track it to see when the next snapshot will be available.
Related
Goal - I want to be able to write selenium tests, using Junit 5, and testcontainers. I am writing a very simple code to just be able to check an attribute of the search bar of google's homepage.
Issue - chrome.getWebDriver(); returns null. Am I missing something?
exception - java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.WebDriver.manage()" because "driver" is null.
this is caused as I try to set an implicit wait after initializing WebDriver.
my pom.xml -
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<test-containers.version>1.16.0</test-containers.version>
<selenium.version>3.141.59</selenium.version>
<junit.version>5.8.1</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${test-containers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>selenium</artifactId>
<version>${test-containers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${test-containers.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
My test class -
#TestInstance(Lifecycle.PER_CLASS)
#Testcontainers
public class GoogleTest {
#Container
public BrowserWebDriverContainer<?> chrome = new BrowserWebDriverContainer<>()
.withCapabilities(Config.getChromeOptions());
private GooglePage googlePage;
#BeforeAll
public void setup() throws Exception {
// ISSUE IS WITH THE LINE BELOW
WebDriver driver = chrome.getWebDriver();
driver.manage().timeouts().implicitlyWait(7, TimeUnit.SECONDS);
// trying to use page object model, just navigates to the google homepage
googlePage = new GooglePage(driver);
}
#Test
public void testTitle() throws Exception {
WebElement element = googlePage.getSearchBar();
Thread.sleep(5000);
assertEquals(element.getAttribute("role"), "combobox");
}
}
In case you need it, the google drive link for the code
got my mistake, if using junit5, fields should be private static final I think...
I was still using public...
I have a not parameterized but #RepeatedTest. When running the acceptance test, the failsafe plugin throws ParameterResolutionException (no ParameterResolver registered for parameter) for #BeforeEach method (in the testcase parent class) which accepts RepetitionInfo. The pom.xml has for JUnit:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
As I've understood from the documentation (§3.11, §3.13.1), nothing else is required (RepetitionInfoParameterResolver is registered automatically and RepetitionInfo is available #BeforeEach), but it seems I'm wrong. What should I do?
... and now the code :-)
#Retention(RUNTIME)
#SuppressWarnings("javadoc")
#Target(METHOD)
#RepeatedTest(AcceptanceTestUtil.MAX_WEBBROWSER_COUNT)
#Tag("AcceptanceTest")
#Test // <- bug lies here, conflicts with #RepeatedTest
public #interface AcceptanceTest {
}
I have a simple example program that duplicates what I believe is a bug, but in case there are real experts out there who know better than I do what's going on, I'll post my issue here.
Here is my Main class:
public class Main {
public static final String BASE_URI = "http://0.0.0.0:8080/myapp/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig()
.packages("com.example")
.register(EntityFilteringFeature.class)
.register(JacksonFeature.class)
;
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.shutdown();
}
}
And here's my Jersey resource:
#Path("myresource")
#Produces(MediaType.APPLICATION_JSON)
public class MyResource {
public static class InnerDataBase {
}
public static class InnerData extends InnerDataBase {
public String item1 = "item1";
public String item2 = "item2";
}
public static class Data {
public String name = "Got it!";
public InnerDataBase innerData = new InnerData();
}
#GET
public Data getIt() {
return new Data();
}
}
The item of note here is that I'm marshalling a class that contains a field whose concrete instance is a derived class with two fields ("item1" and item2") but whose type is actually that of the base class which has no fields. When I run this server and hit the endpoint, I get this:
{"name":"Got it!","innerData":{}}
If I comment out registration of EITHER the EntityFilteringFeature OR the JacksonFeature, the output becomes (as it should):
{"name":"Got it!","innerData":{"item1":"item1","item2":"item2"}}
Conclusion: It appears that the the Jackson media feature is not quite ready for prime time yet in Jersey 2.26-b09.
Additional Thoughts: When I comment out the JacksonFeature, I presume entity filtering is then done with the default Moxy provider. When I comment out EntityFilteringFeature, I presume then that jackson just takes over and handles marshalling for Jersey automatically.
Here's the dependencies section of my pom:
<properties>
<jersey.version>2.26-b09</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
</dependency>
<!-- both json modules may be included as they're enabled in the ResourceConfig -->
<dependency> <!-- use this one when using moxy json processing -->
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
<dependency> <!-- use this one when using jackson json processing -->
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
</dependencies>
Your thoughts? Am I missing something important here?
I'm working on converting some models in a spring-boot REST API app to use java 8's java.time.LocalDateTime instead of joda's DateTime. I want the timestamps returned from API call to adhere to the ISO_8601 format. Motivation is to be forward compatible with Java 8's time (more here).
The part that's proving difficult is when it comes to serialize an object containing LocalDateTime to JSON.
For example, I have the following entity:
// ... misc imports
import java.time.LocalDateTime;
import java.time.ZoneOffset;
#Data
#Entity
#Table(name = "users")
public class User {
#Id #Column
private String id;
#Column
private String name;
#Column
private String email;
#Column
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "UTC")
private java.time.LocalDateTime createdAt;
public User(String name, String email) {
this.id = Utils.generateUUID();
this.createdAt = LocalDateTime.now(ZoneOffset.UTC);
}
}
I have also set my application.properties to turn off the dates as timestamp jackson feature:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
My maven deps:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.1.Final</version>
</dependency>
Finally, I try to retrieve the JSON representation via controller:
#RequestMapping("/users")
#RestController
public class UserController {
private UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public User getUser(#PathVariable("id") String id) {
return userService.findById(id);
}
}
When I actually make a call to this endpoint, I get the following exception:
java.lang.NoSuchMethodError:
com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;
Alternately I also configured the app's ObjectMapper in the configuration class:
#Configuration
public class ServiceConfiguration {
#Bean
public ObjectMapper getJacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(
com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
false
);
return objectMapper;
}
}
Any leads will be greatly appreciated.
UPDATE:
Turns out it was a version mismatch between Spring Boot's Jackson version and the one I had in my pom.xml. As Miloš and Andy proposed, once I've set the correct version and run the app with spring.jackson.serialization.write_dates_as_timestamps=true, the issue was resolved, without needing to configure the ObjectMapper or adding annotations on my LocalDateTime model fields.
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
</dependencies>
The NoSuchMethodError is because you are mixing versions of Jackson. Spring Boot 1.3.6 uses Jackson 2.6.7 and you are using 2.8.1 of jackson-datatype-jsr310.
Spring Boot provides dependency management for Jackson, including jackson-datatype-jsr310, so you should remove the version from your pom. If you want to use a different version of Jackson, you should override the jackson.version property:
<properties>
<jackson.version>2.8.1</jackson.version>
</properties>
This will ensure that all your Jackson dependencies have the same version, thereby avoiding problems with mismatched versions.
You can also, if you wish, remove your Java code that's configuring the ObjectMapper. The Java Time module will be automatically registered when it's in the classpath and writing dates as timestamps can be configured in application.properties:
spring.jackson.serialization.write-dates-as-timestamps=false
Your ObjectMapper bean must be marked as #Primary in order to be picked up by Spring. Alternatively, you can just create a JavaTimeModule bean and it will get picked up by Spring and added to the default object mapper.
You've probably seen it already but take a look at the official documentation.
The error occurs because you mix versions of Jackson. You are using version 1.3.6.RELEASE of Spring Boot. If you would migrate to Spring Boot version 2.x.x.RELEASE then you can replace the com.fasterxml.jackson.datatype dependency by a spring-boot-starter-json dependency. In this way you let Spring Boot take care of the correct Jackson version.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
Actually i am trying to generate swagger.json for my REST services.
i succeeded to do it using jersy, but now we use don't use jersy in our services, we just use Jax-rs, so now i am not able to generate it and got 404 error code.
Here are my pom dependencies
<dependencies>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
and this is my app config application
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.skios.endpoint.EmployeeEndpoint;
import com.skios.endpoint.ShopsEndpoint;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
#ApplicationPath("api")
public class AppConfiguration extends Application {
public AppConfiguration() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setSchemes(new String[] { "http" });
beanConfig.setHost("localhost:7070");
beanConfig.setBasePath("app");
beanConfig.setResourcePackage("com.skios.endpoint");
beanConfig.setScan(true);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet();
resources.add(ShopsEndpoint.class);
resources.add(EmployeeEndpoint.class);
// ...
resources.add(ApiListingResource.class);
resources.add(SwaggerSerializers.class);
return resources;
}
}
and these are my end points
#Api(value = "/employees", description = "Endpoint for employee listing")
#Path("/employees")
public class EmployeeEndpoint {}
#Path("/shops")
#Api(value="/shops", description="Shops")
public class ShopsEndpoint {}
andnow when i am trying to enter the path of swagger.json file
http://localhost:7070/MavenSwaggerTest/api/swagger.json
i got 404 error code.
so what is the problem? can any one help me?
thanks
You haven't configure your ApplicationPath and BasePathcorrectly.
Configure it like this.
#ApplicationPath("/api")
beanConfig.setBasePath("/api");
Now http://localhost:7070/MavenSwaggerTest/api/swagger.json would work, unless there is any other issue.