I have Spring Boot console application which accepts user input. In the same application, there are service to perform some logic.
On running the service's JUnit test case directly, I am observing a behavior where the console application stays in the state of accepting user input, and thus not entering the JUnit tests.
Usually there is no issue becasue for a normal Spring Boot application, there is nothing to run on start up. But for this console application setup, it awaits user input.
May I know if there is any way that can make the test cases run while not triggering the console application? Thank you very much.
Observation: The console application is triggered on JUnit test case run, test case is not entered
Main application
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ToyRobotApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ToyRobotApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
// Instruct user to perform input
System.out.println("Welcome to toy robot application!");
System.out.println("Below are the possible operations:");
System.out.println("PLACE <x-coordinate> <y-coordinate> <facing>");
System.out.println("MOVE");
System.out.println("LEFT");
System.out.println("RIGHT");
System.out.println("REPORT");
while (true) {
System.out.println("Please enter your command:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String usrInput = br.readLine();
//...
}
}
}
Test case
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.somecompany.model.Facing;
import com.somecompany.model.Location;
import com.somecompany.model.Robot;
import com.somecompany.service.ToyRobotService;
#SpringBootTest
public class ToyRobotReportTest {
#Autowired
private Robot robot;
#Autowired
private ToyRobotService toyRobotService;
#Test
public void shouldBeAbleToReportLocation() {
Location location = new Location();
location.setXCor("1");
location.setYCor("2");
location.setFacing(Facing.NORTH);
robot.setLocation(location);
// Actual result
String result = toyRobotService.report();
// Assertion
assertEquals("1,2,NORTH", result);
}
}
Note: Other sources omitted
I got the setup working after some research. To get this to work, the JUnit test class should not be annotated with the usual #SpringBootTest annotation.
When the class is annotated with #SpringBootTest, it will start up the application's context (i.e. start the application). In most usual test scenarios, this should be fine if there is no waiting of user input.
In our case, we want the Spring Boot annotations (e.g. #Autowired) to be recognized, but do not want the application itself to be started up.
We can use the following in JUnit:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = ToyRobotApplication.class, initializers = ConfigDataApplicationContextInitializer.class)
public class ToyRobotPlaceTest {
...
}
This will regonize spring annotations, but will not start the application context.
Related
Been trying to learn/perform some automated testing using Selenium + JUnit + Cucumber and I've spent hours browsing through the internet trying to resolve this with no success. I've written my feature, steps and runner code and the 'glue' is mapped to the correct package too. However, I run into the topic error when I try to run my Runner.java file.
Project Structure
Feature file:
Feature: Admin login
Scenario: Logging into Fleet Portal
Given user navigates to Fleet Portal
When enter credentials
Then user had logged
Runner file:
package Runner;
import org.junit.runner.RunWith;
import io.cucumber.junit.*;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "Features"
,glue="Steps"
)
public class TestRunner {}
Step file:
package Steps;
import java.util.ArrayList;
import java.util.Scanner;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
class App {
private static final WebDriver driver = new ChromeDriver();
public void myMethod(String flag) {
System.out.println(flag);
}
#Given("user navigates to Fleet Portal")
public void user_navigates_to_fleet_portal() {
throw new io.cucumber.java.PendingException();
}
#When("enter credentials")
public void enter_credentials() throws InterruptedException {
throw new io.cucumber.java.PendingException();
}
#Then("user had logged in successfully")
public void user_had_logged_in_successfully() {
myMethod("yes");
throw new io.cucumber.java.PendingException();
}
}
I've tried to take JUnit out of the picture by simply running the feature file as a cucumber test but it still results in the same error, which is weird because the cucumber plugin confirms that the steps are mapped to the features -> feature mapping
POM file
Any and all help is appreciated.
So I am debugging this application that is returning null on emails in the Login method. When using Postman to check data. I am using IntelliJ. My userbean works, but when I try to use the repository it blows up with several exceptions.
public UserServiceBean login(UserServiceBean userServiceBean) {
//set the flag to false
userServiceBean.setSuccess(false);
User user =
userRepository
.findByUsernameAndPassword(
userServiceBean.getUsername(),
userServiceBean.getPassword());
if(null != user) {
BeanUtils.copyProperties(user, userServiceBean);
userServiceBean.setSuccess(true);
}
return userServiceBean;
I am first time ever trying to write Junit testing for this code, I am completely lost on why this isn't working. We are using Java8, mongoDB and Springboot...
import static org.junit.jupiter.api.Assertions.assertEquals;
import edu.team3.cocktailapp.beans.UserServiceBean;
import edu.team3.cocktailapp.models.User;
import edu.team3.cocktailapp.repositories.UserRepository;
import edu.team3.cocktailapp.services.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
I think my repository isn't working right?? Or maybe its coded wrong?? Most of the errors were with MongoDB regarding the repository-
Errors thrown
#SpringBootTest
class CocktailappApplicationTests {
#Autowired
UserRepository repository;
#Test
void testUserService() {
//testing login
UserService service = new UserService();
UserServiceBean bean = new UserServiceBean();
bean.setEmail("bean#testing");
bean.setUsername("Frank");
bean.setPassword("password");
assertEquals(bean.getUsername(), "Frank");
assertEquals(bean.getEmail(), "bean#testing");
assertEquals(bean.getPassword(), "password");
//testing repository
repository.save(
new User(
bean.getUsername(),
bean.getEmail(),
bean.getPassword()
)
);
UserServiceBean login = service.login(bean);
Any kind of help would be greatly appreciated-
I am very trying the pact-jvm-provider-junit using IntelliJ IDEA as my IDE.
I'm testing out the provided ContractTest example:
import org.junit.BeforeClass;
import org.junit.Before;
import org.junit.ClassRule;
import au.com.dius.pact.provider.junit.State;
import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit.target.TestTarget;
import au.com.dius.pact.provider.junit.target.Target;
import au.com.dius.pact.provider.junit.target.HttpTarget;
import au.com.dius.pact.provider.junit.TargetRequestFilter;
import org.apache.http.HttpRequest;
import au.com.dius.pact.provider.junit.PactRunner;
import au.com.dius.pact.provider.junit.loader.PactFolder;
import au.com.dius.pact.provider.junit.loader.PactUrl;
import au.com.dius.pact.provider.junit.VerificationReports;
import com.github.restdriver.clientdriver.ClientDriverRule;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import static com.github.restdriver.clientdriver.RestClientDriver.giveEmptyResponse;
import static com.github.restdriver.clientdriver.RestClientDriver.onRequestTo;
#RunWith(PactRunner.class) // Say JUnit to run tests with custom Runner
#Provider("uicc_repository") // Set up name of tested provider
//#PactFolder("rs") // Point where to find pacts (See also section Pacts source in documentation)
#PactUrl(urls = {"file:///C:/IdeaProjects/src/pack-test-provider/resources/test_consumer-test_provider.json"}) // Point where to find pacts (See also section Pacts source in documentation)
#VerificationReports(value = {"markdown","json"}, reportDir = "C:/IdeaProjects/src/pack-test-provider/resources")
public class ContractTest {
// NOTE: this is just an example of embedded service that listens to requests, you should start here real service
#ClassRule //Rule will be applied once: before/after whole contract test suite
public static final ClientDriverRule embeddedService = new ClientDriverRule(6060);
private static final Logger LOGGER = LoggerFactory.getLogger(ContractTest.class);
#BeforeClass //Method will be run once: before whole contract test suite
public static void setUpService() {
//Run DB, create schema
//Run service
//...
}
#Before //Method will be run before each test of interaction
public void before() {
// Rest data
// Mock dependent service responses
// ...
embeddedService.addExpectation(
onRequestTo("/data"), giveEmptyResponse()
);
}
#TestTarget // Annotation denotes Target that will be used for tests
public final Target target = new HttpTarget(6060); // Out-of-the-box implementation of Target (for more information take a look at Test Target section)
#State("default") // Method will be run before testing interactions that require "default" or "no-data" state
public void toDefaultState() {
// Prepare service before interaction that require "default" state
// ...
System.out.println("Now service in default state");
LOGGER.info("Now service in default state");
}
}
But when I try to run the test (Run -> Run ContractTest), it's like the test is not ran at all:
Mar 15, 2017 3:24:00 PM org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines
INFO: Discovered TestEngines with IDs: [junit-jupiter, junit-vintage]
Mar 15, 2017 3:24:01 PM org.junit.vintage.engine.execution.TestRun lookupTestDescriptor
WARNING: Runner au.com.dius.pact.provider.junit.PactRunner on class rs.ContractTest reported event for unknown Description: rs.ContractTest. It will be ignored.
Process finished with exit code 0
enter image description here
I am not sure if it's an issue with how I am running the test in IntelliJ or I am missing something in the pact-jvm-provider "runner".
Appreciate any help on this topic.
Thanks!
I am writing automatic tests using Java with Selenium Grid and JUnit framework and I have encountered a problem with user input. So my code looks like this:
package com.example.tests;
import com.thoughtworks.selenium.DefaultSelenium;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Scanner;
import static org.junit.Assert.fail;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
public class test {
private DefaultSelenium selenium;
#Before
public void setUp() throws Exception {
selenium = new DefaultSelenium("localhost", 5555, "*googlechrome", "www.google.com");
selenium.start();
}
#Test
public void Test() throws Exception {
// some tests here
}
#After
public void tearDown() throws Exception {
selenium.stop();
}
I would like to add a user input, so when user types for example "Google Chrome", the test will start with Google Chrome, when he types "Firefox", the test will start with Firefox etc. I have tried to put
Scanner in = new Scanner(System.in);
String web_browser = in.next();
somwhere in my code (in setUp method for example), but when the program starts, I can't type anything in the console. Does anyone know the solution for this?
It's tricky dealing with System.in in the test.
I suggest that you rather read your driver preference as a system property?
String driver = System.getProperty("driver");
if (driver != null) {
//use that driver
}
else {
//use default driver
}
You can the launch your test like
mvn test -Ddriver=chrome
or by setting them in your IDE
I have a Spring Shell-based application and a couple of scripts. Is there an easy way to run the scripts in a JUnit test such that a test fails, if some exception/error occurs during the execution of the script?
The purpose of the tests is to make sure that all correct scripts run without errors.
Update 1:
Here's a little helper class for running scripts in JUnit:
import org.apache.commons.io.FileUtils;
import org.springframework.shell.Bootstrap;
import org.springframework.shell.core.CommandResult;
import org.springframework.shell.core.JLineShellComponent;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static org.fest.assertions.api.Assertions.*;
public class ScriptRunner {
public void runScript(final File file) throws IOException
{
final Bootstrap bootstrap = new Bootstrap();
final JLineShellComponent shell = bootstrap.getJLineShellComponent();
final List<String> lines = FileUtils.readLines(file);
for (final String line : lines) {
execVerify(line, shell);
}
}
private void execVerify(final String command, final JLineShellComponent shell) {
final CommandResult result = shell.executeCommand(command);
assertThat(result.isSuccess()).isTrue();
}
}
You can create an instance of Bootstrap, get the shell out of it and then executeCommand() (including the shell command) on it.
You may be interested in what is done in Spring XD for this: https://github.com/spring-projects/spring-xd/blob/master/spring-xd-shell/src/test/java/org/springframework/xd/shell/AbstractShellIntegrationTest.java (although there are a lot of XD specific details)