Why jdbc driver is not found from generated jar? [duplicate] - java

This question already has answers here:
Whats the best way to bundle the whole project in Maven?
(3 answers)
Closed 4 years ago.
I have a JAVA SE project that works fine. The problem arises when I try to use it externally as a jar.
I'm using Eclipse Oxygen. My JAVA SE project, as you can see in my pom, uses JDBC4.2. Oracle doc states:
"In previous versions of JDBC, to obtain a connection, you first had
to initialize your JDBC driver by calling the method Class.forName."
Moreover:
Any JDBC 4.0 drivers that are found in your class path are
automatically loaded. (However, you must manually load any drivers
prior to JDBC 4.0 with the method Class.forName.)
For this reason, I do not need to write Class.forname(...) in DBConnection class (see below).
When I use DBConnection in my project, it works properly, but, if I create a jar and try to import it in another project, I get the following exception: "No suitable driver found for jdbc:postgresql://host:port/dbName". The following are the steps I do to create the jar:
mvn clean install
create new java project (TestProject) in a new empty clean workspace
create a test class with main
call a class that uses DBConnection from main
I have no compilation problem (all the classes from the jar are loaded correctly)
When I run the main, "getConnection" of my DBConnection class throws the following exception: "No suitable driver found for jdbc:postgresql://host:port/dbName"
If I right click on TestProject-> configure -> convert to maven project, then add postgres driver dependency, it all works fine!!!.
Shouldn't the PostgreSQL driver already be present in my jar? Why should I add it in the dependencies of the user project?
The following is the code of the class DBConnection:
package generic.util;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class DBConnection {
private static final String FILE_NAME = "db";
private static final String URL = "url";
private static final String USER = "user";
private static final String PASSWORD = "password";
private static Connection conn;
private DBConnection(){
}
public static synchronized Connection getConnection() throws SQLException, ClassNotFoundException, IOException {
if(DBConnection.conn == null || DBConnection.conn.isClosed()){
Properties props = PropertiesReader.readPropertyFile(FILE_NAME);
String url = props.getProperty(URL);
String user = props.getProperty(USER);
String password = props.getProperty(PASSWORD);
Connection conn = DriverManager.getConnection(url, user, password);
DBConnection.conn = conn;
}
return DBConnection.conn;
}
}
The following is my pom:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupid</groupId>
<artifactId>artifactid</artifactId>
<version>1.0</version>
<properties>
<skipTests>true</skipTests>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>${skipTests}</skipTests>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.2</version>
</dependency>
</dependencies>
</project>

The default behaviour does not repackage dependend libraries into the created artifacts. Usually external libraries will not changed as often as your software does, and will be deployed to an application server.
With microservices e.g. spring-boot this has changed and you can deploy a single .jar file including all dependencies (even tomcat is included).
You have two options:
Put all libraries in a lib-folder and add it to the classpath.
Create a fat jar

Related

How do I include src/test/java files to run TestNG tests?

I'm just learning Java and could use your help. I'm using Eclipse, and created a Maven project using the org.openjfx archetype. Everything seems to work fine except when I try to write tests in src/test/java, which causes an error.
An error occurred while instantiating class
starcraft.warcraft.test.TestClass: Unable to make public
starcraft.warcraft.test.TestClass() accessible: module
starcraft.warcraft does not "exports starcraft.warcraft.test" to
module org.testng
This is how I created the project with default settings in Eclipse:
Project Setup with Maven Archetype Selection
Now, when Eclipse creates the project, it doesn't have a src/test/java folder, so I create that manually. Then I create a class called "TestClass" inside a package "starcraft.warcraft.test" inside src/test/java, and I add a simple method to test inside the App class called "adder". You can see the project structure
Project Structure
package starcraft.warcraft;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage stage) {
var javaVersion = SystemInfo.javaVersion();
var javafxVersion = SystemInfo.javafxVersion();
var label = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
var scene = new Scene(new StackPane(label), 640, 480);
stage.setScene(scene);
stage.show();
}
// WILL TEST THIS METHOD
public static int adder(int digit1, int digit2) {
return digit1 + digit2;
}
public static void main(String[] args) {
launch();
}
}
Now I want to use TestNG for the tests, and so I include it in my POM which is
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>starcraft</groupId>
<artifactId>warcraft</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>starcraft.warcraft.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This is the default POM created by the Maven archetype except for the TestNG dependency I added. When I try to use TestNG, Eclipse makes me add it to the module path like so:
Maven saying I need to add the TestNG library
And here is my module-info:
module starcraft.warcraft {
requires javafx.controls;
requires org.testng;
exports starcraft.warcraft;
}
OK, all good so far, but now when I try to run my test inside TestClass:
package starcraft.warcraft.test;
import org.testng.annotations.Test;
import starcraft.warcraft.App;
public class TestClass {
#Test
public void testAdder() {
int sum = App.adder(1, 2);
System.out.println(sum);
}
}
I get the error, which again is
An error occurred while instantiating class
starcraft.warcraft.test.TestClass: Unable to make public
starcraft.warcraft.test.TestClass() accessible: module
starcraft.warcraft does not "exports starcraft.warcraft.test" to
module org.testng
I can't figure out how to do the export. When I try making the entry in module-info, it doesn't give me the option of adding the package in src/test/java, the only packages it allows me to choose from are in src/main/java.
I don't understand modules well. How can I get the program to let me run tests from src/test/java?
Thanks everyone who looked at this. I solved it by following these steps:
Delete module-info.java. This turns it into a nonmodular project which is fine for me. I hesitated to do this because the Maven JavaFX archetype included it, but as it says here somewhere
https://openjfx.io/openjfx-docs/#IDE-Eclipse
you can just delete it after its created.
The problem then if you try to run the project is it will give you a warning that JavaFX isn't included as a module. It will still run, but its best to get rid of this incase of problems down the road. So you need to download the JavaFX libraries, place them in your hard drive, and then include them in your project via VM arguments in Eclipse:
right click project -> Run configuration -> Arguments tab -> add in the VM arguments area something like:
--module-path [fully qualified path to lib folder containing downloaded JavaFX] --add-modules javafx.controls
path would be like "C:\javafx\lib" or wherever you placed the downloaded JavaFX.
Then it should run, and project will still build using Maven, but I'm not sure if its using the JavaFX which is still in the Maven POM or the one I specified on the C drive. But it works. Any help on whats happening there would be appreciated. Thanks

How to import java project as module in java web project using intelijj?

I wanted to use the class from basic java project inside java servlet class which is defined in another project.
I tried importing project as module through the module dependency InteliJ menu.
At compile time ,it is not giving any error ,but after running the server(Glassfish) and calling the servlet it is giving below error.
java.lang.NoClassDefFoundError: com/practise/LogFileCreator at UserLoginValidator.dbConnectionMaker(UserLoginValidator.java:31)>
Please find below code which causing error.
below class is from web project
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.*;
import com.practise.LogFileCreator;
public class UserLoginValidator extends HttpServlet
{
public String LogFilePath="D:\\Logs";
public PrintWriter out;
String errormsg="";
//********************
LogFileCreator l ;
#Override
public void init() throws ServletException {
try {
this.l = new LogFileCreator(LogFilePath); // here i am trying to create object of my class which causing the mentioned error.
l.WriteLog("Hello");
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
}
}
below class is from normal java project
package com.practise;
import java.io.*;
public class LogFileCreator
{
private String filepath;
private StringBuffer sb = new StringBuffer("Log");
private File file;
private FileWriter fileWriter;
private BufferedWriter bufferedWriter;
public PrintWriter p;
public LogFileCreator(String filepath) throws IOException
{
this.filepath=filepath;
String filename=sb.toString().concat(java.time.LocalDate.now().toString());
this.file = new File(this.filepath,filename);
this.fileWriter= new FileWriter(file,true);
if(!file.exists())
{
file.createNewFile();
}
p= new PrintWriter(fileWriter);
}
public void WriteLog(String logMessage){
p.println(java.time.LocalDateTime.now() + " : " + logMessage);
p.flush();
}
}
Here is the image for module dependency I used .
Image
Earlier I was using LogFileCreator.java class from same web project and it was working fine
Here what i am trying to acheive is ,without writing the LogFileCreator class again in web project ,wants to reuse the class written already inside normal java project to print the logs in desired text file .
Any solution/suggestions would be appreciated.
Thank you!
[Edit 1]
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.0.jre11</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>Logging</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!-- String Driver= "com.microsoft.sqlserver.jdbc.SQLServerDriver";-->
<!-- String dbusername="sa";-->
<!-- String dbpassword="Admin#123";-->
<!-- String connectionString="jdbc:sqlserver://localhost:1433;databasename=Users;";-->
<!-- -->
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>
Here What I did which resolved the above problem.
First I converted my first basic java project to maven project .
secondly I added maven dependency for the 2nd project (web project) and also added the jar file (of first project classes ) inside the web INF/lib directory of web project using below option from InteliJ .
Image
The server's classloader does not have a copy of LogFileCreator.class so the class is not on it's classpath.
It is probably how the deployment file (assuming war) was packaged. How are you building the file? Maven, Gradle, neither, etc.?
Edit
I wanted to give a bit more clarity for others who might stumble upon a similar issue. During compile time, the project/module in question was imported; however, maven does not know to package that library in the generated war. When it was deployed to Glassfish, the war did not contain the LogFileCreator class because it was not packaged in the war. The authors solution worked because maven is packaging the module into the war and Glassfish can now find the class.

An internal error occurred during: "Updating Deployment Scanners for Server: WildFly 23"

I'm trying to connect to my http://localhost: 8080/spring-boot-test/ui, but unfortunately I fail because I have errors on Eclips. WildFly 23 theoretically worked, because I normally get their localhost
An internal error occurred during: "Updating Deployment Scanners for Server: WildFly 23".
Could not initialize class org.wildfly.security.auth.client.DefaultAuthenticationContextProvider
An internal error occurred during: "Checking Deployment Scanners for server".
Could not initialize class org.wildfly.security.auth.client.DefaultAuthenticationContextProvider
When I try to redirect the directory in standalone.xml to a target with META-INF and WEB-INF, I come across two ERRORs
ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) WFLYDS0011: The deployment scanner found a directory named META-INF that was not inside a directory whose name ends with .ear, .jar, .rar, .sar or .war. This is likely the result of unzipping an archive directly inside the C:\Users\adame\eclipse-workspace\spring-boot-test\target directory, which is a user error. The META-INF directory will not be scanned for deployments, but it is possible that the scanner may find other files from the unzipped archive and attempt to deploy them, leading to errors.
ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) WFLYDS0011: The deployment scanner found a directory named WEB-INF that was not inside a directory whose name ends with .ear, .jar, .rar, .sar or .war. This is likely the result of unzipping an archive directly inside the C:\Users\adame\eclipse-workspace\spring-boot-test\target\ directory, which is a user error. The WEB-INF directory will not be scanned for deployments, but it is possible that the scanner may find other files from the unzipped archive and attempt to deploy them, leading to errors.
Pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adamkaim.spring</groupId>
<artifactId>spring-boot-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<properties>
<java.version>16</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<packaging>war</packaging>
</project>
App.java
package com.adamkaim.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Address.java
package com.adamkaim.spring;
import org.springframework.stereotype.Component;
#Component
public class Address {
private String address="Wall Street 34";
public String getAddress() {
return this.address;
}
}
Student.java
package com.adamkaim.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Student {
#Autowired
private Address address;
public String showInfo(){
return this.address.getAddress();
}
}
MainView.java
package com.adamkaim.spring;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
#SuppressWarnings("serial")
#SpringUI(path="/ui")
#Title("Titlett")
#Theme("valo")
public class MainView extends UI{
#Override
protected void init(VaadinRequest request) {
final VerticalLayout verticalLayout = new VerticalLayout();
verticalLayout.addComponent(new Label("Welcome"));
Button button = new Button("Click me");
verticalLayout.addComponent(button);
button.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
verticalLayout.addComponent(new Label("Button is clicked.."));
}
});
setContent(verticalLayout);
}
}
I was having the same error when trying to start a Wildfly 19.1.0 container from Eclipse (2021-09). The container seemed to start successful, but this message was driving me crazy.
After a while I came across this message on the Wildfly Google Groups, and this solved my problems!
Adding --add-opens=java.base/java.security=ALL-UNNAMED to eclipse.ini
fixed the issue on my side
Thanks to the original author, Rahim Alizada, in https://groups.google.com/g/wildfly/c/_OuPrpsF2pY/m/xLt6u-IfBgAJ.
The option --add-opens opens up the informed modules (all types and members) at runtime, allowing deep reflection from the target modules (in this case, everyone else - ALL-UNNAMED).
More about this option in the JEP 261.
I tried running Eclipse with only Java 8 in my system, if I remember it well I got it working, but some modules on these newer Eclipse versions require Java 11 to load properly.
I came across this error during the deployment of wildfly 23 server in eclipse
An internal error occurred during: "Updating Deployment Scanners for Server: WildFly 23". Could not initialize class org.wildfly.security.auth.client.DefaultAuthenticationContextProvider
This solved my issue too
Adding --add-opens=java.base/java.security=ALL-UNNAMED to eclipse.ini

Connecting to MongoDB in Java

I'm following this tutorial to learn how to connect to MongoDB in Java, however, I'm encountering a problem and despite research, I can't seem to fix it.
I do exactly what the tutorial tells me to do:
Create a new Java project
Add mongo-java-driver (I made sure I used the right one including the bson file, which seemed to be the problem in the other questions).
I create a new class and create a new MongoClient
This is my code up until now:
import com.mongodb.MongoClient;
import com.mongodb.DB;
public class MongoDemo {
public static void main(String[] args) {
MongoClient mongoClient = new MongoClient("localhost", 27017);
DB db = mongoClient.getDB("test");
}
}
Now, I think the problem is with how I added the mongo-java-driver, since I get the following error in the first line: The import com.mongodb.MongoClient cannot be resolved but I can't seem to figure out how to fix that.
I did download the correct file and added it as an external library. When I type import com.mongodb. I do get a few suggestions, however, MongoClient is not one of them. What did I do wrong?
You may be looking for something like this.
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoDemo {
public static void main(String[] args) {
ServerAddress serverAddress = new ServerAddress("http://localhost", 27017);
MongoClient mongoClient = new MongoClient(serverAddress);
DB db = mongoClient.getDB("test");
}
}
When creating this, I created a maven project to manage the dependencies better and included the most recent MongoDB dependencies. Here's my POM.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>MongoDBExample</groupId>
<artifactId>MongoDBExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.7.0</version>
</dependency>
</dependencies>
</project>
I haven't tested this, however, notice how some of the code has changed. This is because some of the code used in the demo has been deprecated. This should be close.
In addition to the Dale's answer:
this kind of error may occur due to incorrect addition of driver versions in POM. I recommend you to check properly POM file and try to change versions of mongodb java driver.
Also be attentive and careful with the connection of older and newer drivers, because there is the difference of syntax.
To connect to a standalone MongoDB instance (older drivers like 3.4):
MongoClient mongoClient = new MongoClient();
To connect to a standalone MongoDB instance (newer drivers like 3.8):
MongoClient mongoClient = MongoClients.create()
This difference may not be as noticeable, but adds further problems.
It should work with this code:
ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017");
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).build();
MongoClient mongoClient = MongoClients.create(settings);
MongoDatabase db = mongoClient.getDatabase("test");
The implementation of MongoClient is import com.mongodb.client.MongoClient;
The maven dependency is that one:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.2.3</version>
</dependency>

Very simple step by step JBehave setup tutorial?

Though I have read many, but many articles on how to use JBehave, I can't get it to work. Here are the steps I went through so far:
Created new Java Project
Downloaded JBehave JAR file version 3.6.8 and added it to my build path libraries
Created a package called com.wmi.tutorials.bdd.stack.specs under the test source folder in my workspace
Added the JBehave JAR file to my Build path Library configuration
Created a JBehave story in the above-mentioned package (StackBehaviourStories.story)
Created a Java class in the above-mentioned package (StackBehaviourStory.java)
Created a Java class in the above-mentioned package (StackBehaviourSteps.java)
Imported the Given, Named, Then, When annotations in my Java class
Written two different scenarios in my JBehave story file
And still, I can't get it to work/run! =(
The story file:
Narrative:
In order to learn to with JBehave using Eclipse
As a junior Java developer though senior in .Net and in BDD
I want to define the behaviour of a custom stack
Scenario: I push an item onto the stack
Given I have an empty stack
When I push an item 'orange'
Then I should count 1
Scenario: I pop from the stack
Given I have an empty stack
When I push an item 'apple'
And I pop the stack
Then I should count 0
The story class
package com.wmi.tutorials.bdd.stack.specs
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.junit.JUnitStory;
public class StackBehaviourStory extends JUnitStory {
#Override
public Configuration configuration() { return new MostUsefulConfiguration(); }
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration()
, new StackBehaviourSteps());
}
}
The steps class
package com.wmi.tutorials.bdd.stack.specs
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Named;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
import org.jbehave.core.junit.Assert;
public class StackBehaviourSteps {
#Given("I have an empty stack")
public void givenIHaveAnEmptyStack() { stack = new CustomStack(); }
#When("I push an item $item")
public void whenIPushAnItem(#Named("item") String item) { stack.push(item); }
#Then("I should count $expected")
public void thenIShouldCount(#Named("expected") int expected) {
int actual = stack.count();
if (actual != expected)
throw new RuntimeException("expected:"+expected+";actual:"+actual);
}
}
I'm currently using Eclipse Kepler (4.3) JEE with everything I need to use JUnit, Google App Engine, and yes, JBehave is installed correctly following the Eclipse JBehave installation tutorial.
I can't get it to work. So how can I make it work correctly using Eclipse, JBehave and JUnit?
I know I'm late to the party here but I'm posting because this is the info I wish I had a week ago as it would've saved me a lot of pain. I'm very much into the idea of BDD, but am unfortunately finding JBehave's docs to be a bit of a nightmare, especially when it comes to Maven integration. Moreover a lot of the code I found both on their website and elsewhere didn't work. Through trial and error, and lots of tutorials, I was able to piece together the following. It runs both in Maven and Eclipse, has a single binding class that maps stories to step files, and is able to find story files located in src/test/resources.
here is a working pom file:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.projectvalis.st1</groupId>
<artifactId>st1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>st1</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument></compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${failsafe.and.surefire.version}</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.jbehave</groupId>
<artifactId>jbehave-maven-plugin</artifactId>
<version>4.0.2</version>
<executions>
<execution>
<id>run-stories-as-embeddables</id>
<phase>integration-test</phase>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<ignoreFailureInStories>false</ignoreFailureInStories>
<ignoreFailureInView>false</ignoreFailureInView>
<systemProperties>
<property>
<name>java.awt.headless</name>
<value>true</value>
</property>
</systemProperties>
</configuration>
<goals>
<goal>run-stories-as-embeddables</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.jbehave</groupId>
<artifactId>jbehave-core</artifactId>
<version>4.0.2</version>
</dependency>
</dependencies>
</project>
here is a sample story file
Narrative:
In order to work with files to compress
As a guy who wants to win a bet with cameron
I want to ensure files are ingested and processed in the manner in which the
methods in the ingest class purport to process them.
Scenario: Simple test to give JBehave a test drive
Given a file, a.log
When the caller loads the file as a byte array
Then the byte array that is returned contains the correct number of bytes.
here is a sample step file
package com.projectvalis.compUtils.tests.ingest;
import java.io.File;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Named;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
import org.jbehave.core.steps.Steps;
import org.junit.Assert;
import com.projectvalis.compUtils.util.fileIO.Ingest;
/**
* BDD tests for the ingest class
* #author funktapuss
*
*/
public class LoadByteSteps extends Steps {
private String fNameS;
private byte[] byteARR;
#Given("a file, $filename")
public void setFileName(#Named("filename") String filename) {
File file = new File(getClass().getResource("/" + filename).getFile());
fNameS = file.getPath();
}
#When("the caller loads the file as a byte array")
public void loadFile() {
byteARR = Ingest.loadFile(fNameS);
}
#Then("the byte array that is returned contains the "
+ "correct number of bytes.")
public void checkArrSize() {
File file = new File(fNameS);
Assert.assertTrue(
"loading error - "
+ "the file and the resultant byte array are different sizes!",
(long)byteARR.length == file.length());
}
}
and here is the generic runner
package com.projectvalis.compUtils.tests.runner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
import org.jbehave.core.steps.Steps;
import com.projectvalis.compUtils.tests.ingest.LoadByteSteps;
/**
* generic binder for all JBehave tests. Binds all the story files to the
* step files. works for both Eclipse and Maven command line build.
* #author funktapuss
*
*/
public class JBehaveRunner_Test extends JUnitStories {
#Override
public Configuration configuration() {
return new MostUsefulConfiguration()
.useStoryLoader(
new LoadFromClasspath(this.getClass().getClassLoader()))
.useStoryReporterBuilder(
new StoryReporterBuilder()
.withDefaultFormats()
.withFormats(Format.HTML, Format.CONSOLE)
.withRelativeDirectory("jbehave-report")
);
}
#Override
public InjectableStepsFactory stepsFactory() {
ArrayList<Steps> stepFileList = new ArrayList<Steps>();
stepFileList.add(new LoadByteSteps());
return new InstanceStepsFactory(configuration(), stepFileList);
}
#Override
protected List<String> storyPaths() {
return new StoryFinder().
findPaths(CodeLocations.codeLocationFromClass(
this.getClass()),
Arrays.asList("**/*.story"),
Arrays.asList(""));
}
}
the runner lives in src/test/java//tests.runner.
the ingest test lives in src/test/java//tests.ingest.
the story files live in src/test/resources/stories.
As far as I can tell, JBehave has LOTS of options, so this certainly isn't the only way of doing things. Treat this like a template that will get you up and running quickly.
full source is on github.
Following step by step closely the jbehave Getting Started tutorial, the Run story section says: [...] the ICanToggleACell.java class will allow itself to run as a JUnit test.
This means that the JUnit library is required in your Build path.
Using Eclipse:
Select your current project and right-click it, Build path, Configure Build Path...
Properties for [current project], Java Build Path, Libraries, click [Add Library...]
Add Library, select JUnit, click [Next]
JUnit Library, JUnit library version, select the version you wish to use, click [Finish]
Java Build Path, click [OK]
Project Explorer, select your ICanToggleACell.java class, right-click it, then Run As, and click on JUnit Test
So this is the same here as for the above-example code. The StackBehaviourStory.java class should let itself run as a JUnit test after you add the proper library to the Java build path.
In my case, I have extended my Steps class from Steps (from jbehave core)
i had updated the JunitStory to JunitStories and it worked
public class StackBehaviourStory extends JUnitStory ---> JunitStories

Categories

Resources