Running JBehave with Junit 5 Jupiter - java

I'm trying to get some JUnit 4 based JBehave tests running on JUnit 5. In my project I have a single test class for all stories JBehaveTest.
When I run it as a JUnit 5 test JUnit doesn't see any tests. I modified the #Test annotations to their Jupiter equivalents, I changed the assertTrue and assertFalse to their equivalents, etc.
The JUnit 4 test is annotated with a #RunWith annotation, which in JUnit 5 should be a #ExtendWith annotation if I understood correctly. Unfortunately JBehave is not a JUnit 5 extension, so it won't compile.
Can JBehave be used with JUnit 5, and if so, how?
#RunWith(AnnotatedEmbedderRunner.class)
#UsingEmbedder(embedder = Embedder.class, verboseFailures = true, ignoreFailureInStories = false, generateViewAfterStories = true)
public class JBehaveTest implements Embeddable {
private Embedder embedder;
private DotStoryReporter dot = new DotStoryReporter();
private Stage primaryStage;
#Before
public void createStage() throws TimeoutException {
Locale locale = new Locale("fa", "IR");
Locale.setDefault(locale);
primaryStage = FxToolkit.registerPrimaryStage();
}
#Override
#Test
public void run() throws Throwable {
embedder.runStoriesAsPaths(new StoryFinder().findPaths("src/test/resources", Collections.singletonList("**/*.story"), Collections.<String>emptyList()));
}
#Override
public void useEmbedder(Embedder embedder) {
this.embedder = embedder;
MostUsefulConfiguration configuration = new MostUsefulConfiguration();
Steps steps = new Steps();
configuration.useStoryReporterBuilder(
new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(JBehaveTest.class))
.withDefaultFormats()
.withReporters(dot, new MyStoryReporter(new File("test"), steps))
.withFormats(Format.HTML, Format.TXT)
.withFailureTrace(true)
.withFailureTraceCompression(false));
configuration.useStepdocReporter(new DetailedStepReporter());
embedder.useStepsFactory(new InstanceStepsFactory(configuration, steps));
embedder.useConfiguration(configuration);
}
The Gradle test dependencies are:
testCompile 'org.junit.jupiter:junit-jupiter-api:5.2.0'
testCompile 'org.mockito:mockito-core:2.18.3'
testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
testRuntime 'org.junit.platform:junit-platform-launcher:1.2.0'
testCompile 'org.testfx:testfx-core:4.0.+'
testCompile 'org.testfx:testfx-junit5:4.0.+'
testCompile 'org.jbehave:jbehave-core:4.3.2'
testCompile 'de.codecentric:jbehave-junit-runner:1.2.0'

Related

Fail to load ApplicationContext SpringBoot with SpringSecurity and JUnit Jupiter

I'm working on a REST API using Spring Boot. Currently, the V1 of the API is complete. So, I'm implementing Spring Security to manage authentication and authorization.
Since I've implemented Spring Security, my JUnit Jupiter tests does not work (no one works).
I searched a lot a solution on internet, but all answers I found are for JUnit4 and not JUnit5 (so I don't have all required classes).
I got the classical "Fail to load ApplicationContext" error, but I don't know how to solve it.
Can you help me?
Here is my code for one class (UserController):
gradle.build:
plugins {
id 'jacoco'
id 'org.springframework.boot' version '2.6.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.6'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.6'
implementation 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
developmentOnly 'org.springframework.boot:spring-boot-devtools:2.5.6'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.5.6'
implementation 'com.h2database:h2'
runtimeOnly 'com.h2database:h2'
}
test {
systemProperty 'spring.profiles.active', 'test'
useJUnitPlatform()
finalizedBy jacocoTestReport
}
Application:
#SpringBootApplication
public class BackendApplication {
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}
}
UserController sample:
#RestController
#RequestMapping("/api/v1/users")
public class UserController extends AbstractCrudController<User, Long> {
#Autowired
public UserController(CrudService<User, Long> service) { super(service); }
#GetMapping("")
#Override
#Secured({ "ROLE_XXXXX" })
public ResponseEntity<ResponseListDto<User, Long>> findAll() {
return super.findAll();
}
// ...
}
MockedUserControllerTest sample:
#SpringBootTest
public class MockedUserControllerTest {
#Mock
private UserService service;
#InjectMocks
private UserController controller;
private static User user;
private static List<User> users;
#BeforeAll
public static void beforeAll() {
user = new User();
user.setId(1L);
user.setUsername("A user name");
user.setFirstname("First-Name");
user.setLastname("Last-Name");
user.setPassword("A Gre4t P4ssw0rd!");
user.setMail("first-name.last-name#mail.com");
user.setBirthDate(Date.valueOf("1980-01-15"));
user.setKey("A-key");
user.setNewsletter(Boolean.TRUE);
users = List.of(user);
}
#Test
public void testFindAll() {
when(service.findAll()).thenReturn(users);
assertEquals(new ResponseEntity<>(new ResponseListDto<>(users, null, null), HttpStatus.OK),
controller.findAll());
}
//...
}
Thank you in advance for looking my problem.
For a #SpringBootTest you should use #MockBean annotation, because the Spring context will load in order to run the tests. The loaded context will create mocked beans from the dependencies being annotated by #MockBean and it will inject them into that service, which is being tested.
For pure unit tests the #SpringBootTest annotation should be skipped and Mockito (#Mock annotation) can be used. Spring context will not load in this case, the test will focus on that specific class you are testing. With the created Mocks, you can control the behaviour of dependencies, you can arrange different scenarios for your test.
After some other basic researches (how to write tests with junit5 and mockito), I solved my problem myself.
Here is the answer which helped me: https://stackoverflow.com/a/40962941/13523752
What I wanted is a class test only for the controller I specified. So I didn't need the ApplicationContext. That oriented my research.
Note: I'll do other test classes to test all the process. In this tests I'll need the ApplicationContext.
On my test class, I removed the annotation #SpringBootTest to replace it by #ExtendWith(MockitoExtension.class).
The next thing I did is in the #BeforeAll method I have. I had MockitoAnnotations.initMocks(MockedUserControllerTests.class) to load the mocks I annotated.
Now my test work. I only have to extend this solution on all other mocked test classes.
A sample of the test class I have now:
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class MockedUserControllerTest {
#Mock
UserService service;
#InjectMocks
UserController controller;
// ...
#BeforeAll
public static void beforeAll() {
MockitoAnnotations.initMocks(MockedUserControllerTest.class);
// ...
}
// ...
}

JUnit coverage showing red on MockitoAnnotations

I have a Junit test class. When I ran test coverage in eclipse, I see all the test methods and the actual class is showing Green as covered but only the setUp method is showing in Red and also the Sonar test report is showing coverage as 0%. The same setUp() method is showing Green in other classes and also showing covered in Sonar. I am not sure what I am missing here.
#ExtendWith(MockitoExtension.class)
public class AddServiceImplTest {
#InjectMocks
private AddServiceImpl addServiceImpl;
#Mock
private OtherClass otherClass;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test1() {
....
}

How do i initiate Spring #Autowired instances when running a Cucumber test?

I'm able to initiate Spring when i'm debbuging StepDefinitions.java, but running the test from gradle produces null. Do I need an aditional glue?
Produces null: gradle cucumber
Produces null: running myFeature.features
Produces myService (working): running Stepdefinitions.java
I have tried the following code:
#ContextConfiguration(
classes = Application.class,
loader = SpringBootContextLoader.class)
#WebAppConfiguration
Current StepDefinitions:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Application.class)
#WebAppConfiguration
public class StepDefinitions{
private static String roll;
#Autowired
MyService myService;
/** Reset all static values before running test cases */
#BeforeClass
public static void resetValues() {
roll = "";
}
//I use swedish, "Given"
#Givet("Jag har rollen {string}")
public void getRole(String roll) {
assertNotNull(roll);
this.roll = roll;
myService.useRole(roll);
}
}
gradle.build:
dependencies {
compile files('../libs/cucumber-spring-4.7.1.jar')
testCompile 'io.cucumber:cucumber-java:' + cucumberVersion
testCompile 'io.cucumber:cucumber-junit:' + cucumberVersion
...
}
task cucumber() {
dependsOn assemble, compileTestJava
doLast {
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime +
sourceSets.main.output + sourceSets.test.output
args = ['--plugin', 'pretty', '--glue', 'steps/rufs',
'src/test/resources/features', '--tags','#rufs']
}
}
}
You are not getting JUnit involved anywhere when running from Gradle. #RunWith is used by JUnit, and this in turn is what prompts Spring to get involved. When Cucumber is running as your suite, it's ignoring those annotations because it doesn't understand them.
You'll need to use JUnit as your suite (i.e. not run cucumber.api.cli.Main). You then have a problem because you need to use two "runners": Cucumber and Spring.
The way around this is JUnit's "rules" for one of the runners. Spring has a Rule, but as far as I can see Cucumber does not. In this case, use the Cucumber runner:
#RunWith(Cucumber.class)
in combination with Spring's rules, as described here: How to run JUnit SpringJUnit4ClassRunner with Parametrized?

Cucumber Test a Spring Boot Application

Does anyone know where I can find a sample application where Cucumber is used to test a Spring Boot application through Gradle? I can run the tests fine starting the server on the cmd line and using my IDE, but I need to be able to run them all programmatically on the CI server. I saw the answer on here but that solution did not work for me, most likely because I have multiple step def files.
Here is my setup
build.grade (Mentioned in the other question)
testCompile ("org.springframework.boot:spring-boot-starter-test",
...
"info.cukes:cucumber-spring:${cucumberVersion}")
CucumberTest.java
#RunWith(Cucumber.class)
#CucumberOptions(format = "pretty", features = "src/test/resources")
public class CucumberTest{
}
AbstractSpringTest.java (Extended by all the StepDef files)
#SpringApplicationConfiguration(classes = Application.class)
#RunWith(SpringJUnit4ClassRunner.class)
#Ignore
public abstract class AbstractSpringTest
{ ... }
It's not doing the correct thing on start up because its 1. trying to initialize my step def files and 2. My application is not started and the cucumber tests cannot make a connection.
Thanks.
EDIT: Or if someone can tell me how to start and stop the application using gradle, that would be acceptable as well.
I have solved the issue with some help from this question.
Here is the repository with the answer:
https://github.com/jakehschwartz/spring-boot-cucumber-example
In short, the AbstractSpringTest class needs to have the following annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = DemoApplication.class, loader = SpringApplicationContextLoader.class)
#WebAppConfiguration
#IntegrationTest
I had a similar symptom, my cucumber wouldn't start up the Spring context...
Turns out I had missed (one of) the following dependencies:
build.gradle
testCompile "info.cukes:cucumber-junit:1.2.4"
testCompile "info.cukes:cucumber-java:1.2.4"
testCompile "info.cukes:cucumber-spring:1.2.4"
StepDefs.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
loader = SpringApplicationContextLoader.class,
classes = Application.class
)
#WebIntegrationTest(randomPort = true)
public class StepDefs {
#Value("${local.server.port}")
int port;
}
Update: SpringBoot 1.5.1
#ContextConfiguration(
loader = SpringBootContextLoader.class,
classes = Application.class
)
Further to #jakehschwartz, if you want the web app to start on a random available port, AbstractSpringTest needs:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
#WebIntegrationTest({"server.port=0"})
public abstract class AbstractSpringTest {
#Value("${local.server.port}")
protected int serverPort;
...}
I did something like this to get Spring to work with JUnit parameterized tests. It should be the same concept for Cucumber, but I haven't tried it. I was using XML configuration, so that might make a difference.
RunWithSpringJUnit4
public abstract class RunWithSpringJUnit4 {
private TestContextManager testContextManager;
public RunWithSpringJUnit4() {
try {
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
CucumberTest
#RunWith(Cucumber.class)
#CucumberOptions(format = "pretty", features = "src/test/resources")
public class CucumberTest extends RunWithSpringJUnit4 {
}
First, you'll need to ensure that you have applied spring-boot in gradle. Invoke gradle build which will produce a runnable jar. Instead of having your manifest call for the Spring class as your main, have a wrapper that starts it in a thread, waits for it to settle down and runs Cucumber:
#RunWith(Cucumber.class)
public class LucasePsCucumberTest implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(this);
t.start();
// wait for t
cucumber.api.cli.Main(null);
}
}

Programmatically build Junit recursive Suite with Junit4

With annotation, it's easy to set up Junit 'recursive' Suite :
#SuiteClasses({MyTest.class})
public class MySuite{}
then
#SuiteClasses({MySuite.class})
public class MySweetSuite {}
Launching MySweetSuite will launch MySuite that will launch Test.
But how to do this programmatically, to launch the whole thing with JunitCore?
Right now, I can just create the MySuite with
Class<?>[] tests = { MyTest.class};
Suite mySuite = new Suite(myBuilder, tests);
How can I do the 'parent' mySweetSuite ?
According to the jUnit Documentation the TestSuite implements Test.
Therefore try the following:
Class<?>[] testClasses = { MySweetSuite.class }
TestSuite suite = new TestSuite(testClasses);

Categories