Kotlin - running an integration test, error `fun main is already defined` - maven

I have written an integration test for a Web application but I don't know how to run this test. Maven build fails with the following error when I execute mvn test
[INFO] Compiling Kotlin sources from [src/main/kotlin]
[INFO] Classpath: <...>
[INFO] Classes directory is <...>\target\classes
[INFO] Module name is demo
[ERROR] <...>\src\main\kotlin\demo\Application.kt: (9, 1) 'public fun main(args: kotlin.Array<kotlin.String>): kotlin.Unit' is already defined in demo
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Here is my main class (Application.kt)
package demo
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
#SpringBootApplication
open class Application
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
Here is a part of my test class
package demo
import org.junit.runner.RunWith
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.boot.test.WebIntegrationTest
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
import demo.Application
import demo.model.City
import demo.repository.CityRepository
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebIntegrationTest({"server.port=8080"})
class CityControllerTest {
#Autowired
private var cityRepository: CityRepository?
private val restTemplate: RestTemplate = TestRestTemplate()
// ...
}
There is no such error when I execute mvn clean test. So I suppose Kotlin is frightened of previously compiled classes. Though I am very unsure...
What is the right way to run an integration test?

It is a bug (https://youtrack.jetbrains.com/issue/KT-10051). Already fixed and the fix will be delivered very soon

Related

Operation timed out error when running spring-boot:run

I am trying to run through the Spring Quickstart Guide.
I have the DemoApplication.kt file updated to
package com.example.demo
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
#SpringBootApplication
#RestController
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
#GetMapping("/hello")
fun hello(#RequestParam(value = "name", defaultValue = "World") name: String?): String? {
return String.format("Hello %s!", name)
}
When I run ./mvnw spring-boot:run it times out with Exception in thread "main" java.net.ConnectException: Operation timed out.
Stack Trace
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:588)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:639)
at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:304)
at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:174)
at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:183)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:532)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:637)
at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266)
at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380)
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:193)
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1245)
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1131)
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:179)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1668)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1592)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)
at org.apache.maven.wrapper.DefaultDownloader.downloadInternal(DefaultDownloader.java:106)
at org.apache.maven.wrapper.DefaultDownloader.download(DefaultDownloader.java:93)
at org.apache.maven.wrapper.Installer.createDist(Installer.java:86)
at org.apache.maven.wrapper.WrapperExecutor.execute(WrapperExecutor.java:155)
at org.apache.maven.wrapper.MavenWrapperMain.main(MavenWrapperMain.java:72)
Any idea what I need to do differently? Thanks.
The Spring App you wrote wouldn't normally make an outbound connection that could fail - that was what was confusing about the original question.
Now that you have provided the stack trace it is clearer what is going on.
What's happening is that you are compiling and running the app using Maven and Maven needs some more artefacts for your application so it is automatically downloading them for you org.apache.maven.wrapper.DefaultDownloader.download(....
So if you have to use a proxy to reach the Internet, then you need to give these details to Maven. Try this guide: https://maven.apache.org/guides/mini/guide-proxies.html

How to convert XML to String with JAXB and spring-boot?

When I run a mvn spring-boot:run on the folder that has the pom.xml file the application starts and serializes a POJO into a XML correctly, but when I do it by going to the target folder and starting it by using java -jar in the jar file I get javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath caused by .java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory.
In my maven I have the following JAXB dependencies:
<!-- JAXB API -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<!-- JAXB Runtime -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.5</version>
<scope>runtime</scope>
</dependency>
Here's the code that serializes a POJO into XML:
private static final Pattern REMOVE_HEADER = Pattern.compile("\\<\\?xml(.+?)\\?\\>");
public static <T> String toXML(final T data) {
try {
final var jaxbMarshaller = JAXBContext.newInstance(data.getClass()).createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
final var sw = new StringWriter();
jaxbMarshaller.marshal(data, sw);
return XMLUtils.REMOVE_HEADER.matcher(sw.toString()).replaceAll("").strip();
} catch (final JAXBException e) {
XMLUtils.LOGGER.error("Error while converting POJO to XML. ERROR: {}.", e.getMessage(), e);
}
return "";
}
Here's the log when I start the application with java -jar:
2021-12-26 21:19:14,526 [ForkJoinPool.commonPool-worker-11] ERROR com.enterprise.system.shared.util.XMLUtils - Error while converting POJO to XML. ERROR: Implementation of JAXB-API has not been found on module path or classpath..
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:232)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:375)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:691)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:632)
at com.enterprise.system.shared.util.XMLUtils.toXML(XMLUtils.java:26)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:952)
at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:926)
at java.base/java.util.stream.AbstractTask.compute(AbstractTask.java:327)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:92)
at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:125)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:230)
... 17 more
Here's an image of the generated spring-boot fat jar with the JAXB dependencies:
Here's my dependency tree:
--- maven-dependency-plugin:3.2.0:tree (default-cli) # java-eleven-jaxb-hell ---
com.enterprise.system:java-eleven-jaxb-hell:jar:0.0.1-SNAPSHOT
+- org.slf4j:slf4j-log4j12:jar:1.7.32:compile (optional)
| +- org.slf4j:slf4j-api:jar:1.7.32:compile (optional)
| \- log4j:log4j:jar:1.2.17:compile (optional)
+- org.springframework.boot:spring-boot-autoconfigure:jar:2.6.2:compile
| \- org.springframework.boot:spring-boot:jar:2.6.2:compile
| +- org.springframework:spring-core:jar:5.3.14:compile
| | \- org.springframework:spring-jcl:jar:5.3.14:compile
| \- org.springframework:spring-context:jar:5.3.14:compile
| +- org.springframework:spring-aop:jar:5.3.14:compile
| +- org.springframework:spring-beans:jar:5.3.14:compile
| \- org.springframework:spring-expression:jar:5.3.14:compile
+- org.projectlombok:lombok:jar:1.18.22:provided
+- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:compile
| \- jakarta.activation:jakarta.activation-api:jar:1.2.2:compile
\- com.sun.xml.bind:jaxb-impl:jar:2.3.5:runtime
\- com.sun.activation:jakarta.activation:jar:1.2.2:runtime
And finally, here are my model classes:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#XmlRootElement(name = "finans")
#XmlAccessorType(XmlAccessType.FIELD)
#Data
#NoArgsConstructor
#AllArgsConstructor
public class FinanTokenDTO {
#XmlAttribute
private String pln;
#XmlAttribute
private String ope;
#XmlAttribute
private String mod;
#XmlAttribute
private String mis;
#XmlAttribute
private String val;
#XmlAttribute
private String car;
#XmlAttribute
private String dti;
#XmlAttribute
private String dtf;
#XmlAttribute
private String ota;
#XmlElement
private FinanDTO finan;
}
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#XmlRootElement(name = "finan")
#XmlAccessorType(XmlAccessType.FIELD)
#Data
#NoArgsConstructor
#AllArgsConstructor
public class FinanDTO {
#XmlAttribute
private String prd;
#XmlAttribute
private String pkg;
#XmlAttribute
private String val;
#XmlAttribute
private String fty;
}
I am using java 11 and I am aware that in java 11 JAXB was removed from the SE JDK because it is considered as a EE feature.
I am not able to execute it using mvn spring-boot:run in production environment because of the size of the docker image and security related issues using docker container.
Since Spring Boot generates a fat jar, shouldn't the application run with java -jar applied to the spring boot fat jar generated file the same way as it does with mvn spring-boot:run inside the folder with pom.xml?
EDIT:
After a lot of digging and testing I found that the problem occurs when we try to marshall several valid POJOs using parallel stream instead of stream on the POJOs list. I uploaded the code in java-eleven-jaxb-hell to better understanding, unfortunatelly I cannot change parallelStream to stream because of performance issues. Just to remember, for the problem to happen you have to run java -jar against spring-boot generated fat jar in target folder.
Try adding the next dependency:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.1</version>
</dependency>
I suggest you to replace the JAXB-impl from Sun by the one from Glassfish:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.5</version>
</dependency>
Generally speaking, Sun does not exists anymore since years, and the package might be there only for compatibility. The recommended JAXB implementation today comes from Glassfish.

TestNG error from Eclipse while running my Maven project

TestNG Error in Maven ProjectHi Davis and others as well: - Below is my project screenshot and code and i am getting this TestNg Error using Maven Project, please help me on this and I have also attached few screenshots for reference:-
GenerateReports.java
package ExtentReports.GenerateHTMLReports;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;
public class GenerateReports {
ExtentReports E2;
#BeforeTest
public void config()
{
String s1 = System.getProperty("user.dir")+"\\reports\\index1.html";
ExtentSparkReporter E1 = new ExtentSparkReporter(s1);
E1.config().setReportName("MyAutomationReport");
E1.config().setDocumentTitle("GoogleHomePage");
E2 = new ExtentReports();
E2.attachReporter(E1);
E2.setSystemInfo("Tester", "G");
}
#Test
public void initializeDriver()
{
E2.createTest("MyHTMlReportTest");
System.setProperty("webdriver.chrome.driver",
"F:\\Selenium_Training\\Ganesh_Project\\Browser_Drivers\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.google.com");
driver.getTitle();
driver.close();
E2.flush();
}
}
Pom.xml
I am getting a TestNG error while running a Maven project in XML and here is the error message:-
org.testng.TestNGException:
TestNG by default disables loading DTD from unsecured Urls. If you need to explicitly load the DTD from a http url, please do so by using the JVM argument [-Dtestng.dtd.http=true]
at org.testng.xml.TestNGContentHandler.resolveEntity(TestNGContentHandler.java:115)
at com.sun.org.apache.xerces.internal.util.EntityResolverWrapper.resolveEn
Also, i tried the below possibilities and again getting error message which is different from this:-
I tried to add Jvm argument -Dtestng.dtd.http=true and placed it under run -->run configurations-->arguments-->VM arguments in eclipse
After placing the above jvm argument i am getting this new error message in console, do not know how to solve it below is the error after adding jvm argument and running the maven project:-
org.testng.TestNGException: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at org.testng.TestNG.parseSuite(TestNG.java:354)
at org.testng.TestNG.initializeSuitesAndJarFile(TestNG.java:374)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:103)

Run unit tests with spring boot, "no runnable methods" error

I'm running unit tests with Spring boot, but I get a weird no runnable error. The tests pass by the way, but after all test have ended successfully, I get this weird error out of nowhere:
java.lang.Exception: No runnable methods
at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:191)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:137)
at org.springframework.test.context.junit4.SpringRunner.<init>(SpringRunner.java:49)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
How do I fix this? Why is Spring boot looking for a runnable in my tests?
Here is an example of my code
package ca.bell.uc.hello.world
import org.junit.Assert
import org.junit.jupiter.api.Test
import org.junit.runner.RunWith
import org.springframework.test.context.junit4.SpringRunner
#RunWith(SpringRunner::class)
internal class example {
#Test
fun f() {
Assert.assertTrue(true)
}
}
And here is a screenshot of the error:
Thanks
P.S. This is Kotlin
You are trying to use JUnit 5 #Test annotation because of import:
import org.junit.jupiter.api.Test
In the console log we can see that JUnit 4 is used.
If you want to work with JUnit 4 you should use the import:
import org.junit.Test
Indeed it's the mix of JUnit4 and JUnit5. I had the same thing with tests with #Ignore or #Disabled that would not want to get ignored based on which #Test it was.
You can avoid this issue with spring by updating your spring dependencies and remove the Junit4 dependencies from your build.gradle.kts so that you won't mix them (tested with Gradle v6, check the groovy syntax if you use build.gradle).
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
exclude(module = "junit-vintage-engine")
exclude(module = "mockito-core")
}
testImplementation("org.junit.jupiter:junit-jupiter:5.4.2")
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
Once you have that you don't need to use #RunWith(SpringRunner::class) you can see the difference in your import, they should all contains "jupiter" and your class could look like this:
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
internal class ExampleTest {
#Test
fun test() {
Assertions.assertTrue(true)
}
}

Gradle Error in contextLoads under test

i am trying to build a web using Spring and Angular Js tegether w/ Gradle. my problem is When i run my project or build gradle this error comes out.
"contextLoads FAILED"
"What went Wrong:"
.> There were failing tests.: /build/reports/tests/test/index.html
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException
ContextLoad Leads me to this Class:
package com.linkedin.learning.linkedinlearningfullstackappangularspringboot;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class LinkedInLearningFullStackAppAngularSpringBootApplicationTests {
#Test
public void contextLoads() {
}
}
heres the screenshot to make it clearer:
enter image description here

Resources