I am working on the GET request and I am trying to make it generic. I do not understand what is the mistake I have done here. Can any one help me out in tracing this out. The data from excel wil be generic in the GET request. The code can be found below.
Working on: Java, RestAssured, TestNG, Maven
This is my Properties file:
RestAssured.baseURI = http://website.com:8080/DBName;
This is my Readproperties file:
public class DemoTestcase {
String url;
#BeforeSuite
public void SetBrowser() {
System.out.println("Before Suite....");
}
#BeforeMethod
public void load_property_file() throws IOException {
Properties prop = new Properties();
InputStream input = getClass().getClassLoader()
.getResourceAsStream("Configuration/config.properties");
prop.load(input);
System.out.println();
url = prop.getProperty("RestAssured.baseURI");
System.out.println(url);
}
My Code for RestAssured API: Here I am Trying to make it generic by using Data Provider and reading it from excel.
#Test(dataProviderClass = <packageName.className>.class, dataProvider = "urlParameters")
public void tc_008_using_BDD_keywords(final String readExcelData) {
try {
ValidatableResponse response = given()
.when().get(url + "/{readExcelData}").then()
.contentType(ContentType.JSON);
System.out.println(((ResponseBodyData) response).asString());
} catch (Exception e) {
System.out.println("e.printStackTrace()");
}
}
This is my DataProvider. I have written the logic for reading from the excel file and returning as Object [][] to #Test.
#DataProvider(name = "urlParameters")
public static Object[][] createUrlParameters() throws IOException, ParseException {
<//Logic for reading Excel sheet containing 3 row and 1 column>
If I'm correct, you're using the variable wrong:
public void tc_008_using_BDD_keywords(final String readExcelData) {
try {
ValidatableResponse response = given()
.when().get(url + "/{readExcelData}").then()
.contentType(ContentType.JSON);
System.out.println(((ResponseBodyData) response).asString());
} catch (Exception e) {
System.out.println("e.printStackTrace()");
}
}
should be:
public void tc_008_using_BDD_keywords(final String readExcelData) {
try {
ValidatableResponse response = given()
.when().get(url + "/" + readExcelData).then()
.contentType(ContentType.JSON);
System.out.println(((ResponseBodyData) response).asString());
} catch (Exception e) {
System.out.println("e.printStackTrace()");
}}
.get(url + "/{readExcelData}") is reading url/{readExcelData} in Java. You're not using the actual variable.
Related
I mean, this is what i have in my code:
#GetMapping("/get/player/{csvName}")
public void loadPlayers(#PathVariable String csvName) {
/*Irrelevant code here*/
}
This works just because the csv file is in the root of my project.
Is there any way to set the relative path of the csv file on the url?
////////////////////////////////////////////////////EDIT///////////////////////////////////////////////////////
Here is the code of the class:
#RestController
#RequestMapping("/csv")
public class CsvController {
private static final Logger log = LoggerFactory.getLogger(FutbolApplication.class);
#Autowired
private PlayerRepository playerRepository;
#Autowired
private TeamRepository teamRepository;
#Autowired
private MembershipRepository memberRepository;
#GetMapping("/get/player/{csvName}")
public void loadPlayers(#PathVariable String csvName) {
CSVReader reader;
try {
reader = new CSVReaderBuilder(new FileReader(csvName))
.withSkipLines(1).build();
String[] values;
int i;
int count=0;
while ((values = reader.readNext()) != null) {
count++;
i=0;
try {
Player player = new Player(values[i++],values[i++],values[i++],Date.valueOf(values[i++]));
System.out.println(player.getName() + "//" + player.getSurname() + "//" + player.getPosition()
+ "//" + player.getBirthDate());
playerRepository.save(player);
}catch (Exception e) {
log.error("ERROR INTENTANDO ASIGNAR LOS DATOS AL JUGADOR "+(count));
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CsvValidationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
What I can to, is to insert the path of the csv instead of just the name.
At the moment my project's structure is:
>project
>src
>main
>test
>.Settings
>mycsvfile.csv
that's why i can just type "mycsvfile.csv" in the url and it works
But this is what i'd like to get:
>project
>src
>main
>test
>.Settings
>csvs
>mycsvfile.csv
And get it to work by typing "/csvs/mycsvfile.csv"
Because now i just can type "https:localhost:8080/csv/get/player/mycsvfile.csv"
Is it possible?
Use #RequestParam instead of #PathVariable.
If I understood correctly, you want to send the path of the file, you want to load your Player from, via the request.
Sending a file path in the URI won't work from the get go as it will change the path of the request and it will lead to a 404 NOT FOUND.
Using #RequestParam is a different story, you can add full file path there.
#GetMapping("/get/player")
public void loadPlayers(#RequestParam String csvName) {
/*Rest of your code here*/
}
This way your request would look like this:
https://localhost:8080/csv/get/player?csvName=csvs/mycsvfile.csv
If you really want to use #PathVariable to send the path of your file, then you will have to change your endpoint to work with wildcard and extract the file path from the request URI like explained by N. Chicoine here.
And if you need to use this in multiple places you can even get a more elegant solution by implementing an annotation that makes use of the HandlerMethodArgumentResolver interface:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
public #interface FilePath {
class Resolver implements HandlerMethodArgumentResolver {
private final PathMatcher pathMatcher;
public Resolver() {
this.pathMatcher = new AntPathMatcher();
}
#Override
public boolean supportsParameter(MethodParameter methodParameter) {
Annotation annotation = methodParameter.getParameterAnnotation(FilePath.class);
return annotation != null;
}
#Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modeContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest == null) {
return null;
}
String patternAttribute = (String) servletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String mappingAttribute = (String) servletRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
return this.pathMatcher.extractPathWithinPattern(patternAttribute, mappingAttribute);
}
}
}
Then you will have to register the annotation in application configuration:
#Configuration
public class Config implements WebMvcConfigurer {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new FilePath.Resolver());
}
}
And finaly you can use it like this:
#GetMapping("/get/player/**")
public void loadPlayers(#FilePath String csvName) {
/*Rest of your code here*/
}
Enabling you to execute the request like:
https://localhost:8080/csv/get/player/csvs/mycsvfile.csv
Hope this will help you.
I keep getting this error, the path has been specified in yml and even in the console it is going to the relative path but not reading the file or finding it, how can I get past this ?
I have attached the picture and below is the code in my main method. Any input is deeply appreciated. Thanks!
#SpringBootApplication
#EnableConfigurationProperties(DataStaxAstraProperties.class)
public class BookAppApplication {
#Autowired AuthorRepostories authorRepostories;
#Value("${datadump.location.author}")
private String authorDumpsLocation;
#Value("${datadump.location.works}")
private String authorWorksLocation;
public static void main(String[] args) {
SpringApplication.run(BookAppApplication.class, args);
}
private void initAuthors() {
Path path = Paths.get(authorDumpsLocation);
System.out.println(path.toAbsolutePath());
try(Stream<String> lines = Files.lines(path)){
lines.forEach(line->{
String jsonStr = line.substring(line.indexOf("{"));
try {
JSONObject jsonObject = new JSONObject(jsonStr);
Author author = new Author();
author.setName(jsonObject.optString("name"));
author.setPersonalName(jsonObject.optString("personal_name"));
author.setId(jsonObject.optString("key").replace("/authors/",""));
System.out.println("Saving author" + author.getName() + "....");
authorRepostories.save(author);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
private void initWorks() {
}
#PostConstruct
public void start() {
initAuthors();
initWorks();
}
#Bean
public CqlSessionBuilderCustomizer sessionBuilderCustomizer(DataStaxAstraProperties astraProperties) {
Path bundle = astraProperties.getSecureConnectBundle().toPath();
return builder -> builder.withCloudSecureConnectBundle(bundle);
}
}
found the issue. Had to do with access rights. Java couldn't access the files because it was secured after changing the property of a file, it worked.
I want to get one line as header and then rest of data append in the file.but i am facing issue that it is saving the header repeatedly when i have called the function.
Expected output should be like
Id : Title : Group ID
1 : ab : 2
2 : fd : 3
3 : fwsj : 3
public void writeOutputToFile(int id, String title, int groupId) throws IOException {
OutputStream os = new FileOutputStream(new File("output_report.txt"), true);
os.write("\n Id Title Group ID \n ".getBytes());
os.write((id + " " +title + " " + groupId + "\n").getBytes());
os.close();
}
well, inside your method you write the headers to the file, so obviously whenever you call it they'll get written..
You can separate it to two methods- one that writes the headers (and called only once) and another that writes the data (and called once per row).
Alternatively, use some sort of loop inside your method to write each of the lines to the file, after writing the headers once.
The Problem
It is repeatedly putting in the header, because when you call the method, you are always going to insert the header. Instead, you may want to code a util that inputs headers for a file you are creating, and then a separate method for inserting the data.
The Solution
Solution 1)
The helper util method would look something like this:
// String... allows for multiple string parameters to be entered for all of your headers.
public void prepFile(File f, String... headers) {
StringBuffer buffer = new StringBuffer();
for (String header : headers) {
buffer.append(header + "\t");
}
OutputStream os = new FileOutputStream(f, true);
os.write(buffer.toString().getBytes());
os.close();
}
After the file is prepped, you can then use your writeOutputToFile method for all the data.
Edit
Solution 2)
If you were going to make a stand alone class for this, I would recommend you set it up like so:
import java.io.*;
public class OutputFile {
private File file;
private String[] headers;
private boolean existed;
public OutputFile(File f, String... headers) {
this.file = f;
this.headers = headers;
init();
}
private void init() {
existed = file.exists();
// If the file didn't exist, then you want to create it.
if (!existed) {
try {
file.createNewFile();
// Afterwards, you can then write your headers to it.
if (headers != null) {
writeData(headers);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void writeData(int id, String title, int groupId) {
writeData("" + id, title, "" + groupId);
}
public void writeData(String... strings) {
StringBuffer buffer = new StringBuffer();
for (String s : strings) {
buffer.append(s + "\t");
}
buffer.append("\n");
writeData(buffer.toString());
}
public void writeData(String data) {
OutputStream os = null;
try {
os = new FileOutputStream(file, true);
os.write(data.getBytes());
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
This question already has answers here:
Mocking Files in Java - Mock Contents - Mockito
(3 answers)
Closed 6 years ago.
I have the following code:
public class FolderServiceImpl implements FolderService {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
if (folderStatusFile.exists()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(folderStatusFile));
String line = br.readLine();
status = Integer.parseInt(line);
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
L.warn("could not close reader ", e);
}
}
}
} else {
status = 3;
}
return status;
}
}
I want to test this method without creating actual files for every case. I should be using Java 1.7, JUnit 4, Mockito and/or PowerMockito.
Any ideas on how to do that?
I am talking about mocking either the data source or simply changeing the input for the method.
My test looks something like this:
`#Rule
public TemporaryFolder folder = new TemporaryFolder();
private FolderServiceImpl serviceToTest = new FolderServiceImpl();
private String folderPath;
#Before
public void setUp() {
folderPath = folder.getRoot().getAbsolutePath();
try {
folder.newFile(".folderstatus");
} catch (IOException e) {
e.printStackTrace();
}
}
#Test
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() {
// given
deleteFolderStatusFile();
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(3, status);
}
#Test
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() {
// given
writeStatusToTestFile("Test");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(4, status);
}
#Test
public void shouldReturnFolderStatusInTheFile() {
// given
writeStatusToTestFile("1");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(1, status);
}
private void writeStatusToTestFile(String status) {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.write(file, status.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private void deleteFolderStatusFile() {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.delete(file);
} catch (IOException e) {
e.printStackTrace();
}
}`
Although the answer of #BenHeid may work I'd suggest to change to different approach.
IMHO when ever I use PowerMock(-ito) it is a surrender to bad design.
Also the PowerMock solution will confuse test coverage tools since it changes the Applications byte code after it has been instrumented for coverage measurement.
So the approach I'd prefer is to stick to Clean Code and OOP rules.
One of them is separation of concerns.
In your case the method creates some infrastructure classes (dependencies) to work with, namely FileReader and BufferedReader.
But the instantiation of (direct) dependencies is not a responsibility of a class containing business logic.
Therefore I'd suggest to refactor that code out into a separate class:
class ReaderFactory {
public BufferedReader createFor(File file) throws FileNotFoundException {
return new BufferedReader(new FileReader(file));
}
}
Your Class would change to this:
class FolderServiceImpl {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
private final ReaderFactory readerFactory;
FolderServiceImpl(ReaderFactory readerFactory) {
this.readerFactory = readerFactory;
}
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
// try "with resource" takes care of closing the reader
try (BufferedReader br = readerFactory.createFor(folderStatusFile);) {
String line = br.readLine();
status = Integer.parseInt(line);
} catch (IOException e) {
status = 3;
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
}
return status;
}
}
And your Test would be this:
public class FolderServiceImplTest {
private static final String ANY_FILE_NAME = "";
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Rule
public ExpectedException thrown = ExpectedException.none();
#Mock
private ReaderFactory readerFactory;
#InjectMocks
FolderServiceImpl sut;
#Test
public void getStatus_FileNotExisting_returnStatus3() throws Exception {
// arrange
Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class));
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(3));
}
#Test
public void getStatus_ValidFile_returnFileContentAsInt() throws Exception {
// arrange
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class));
Mockito.doReturn("4711").when(bufferedReader).readLine();
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(4711));
}
}
You have to use something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(tests.class)
public class test {
#Test
public void test() throws Exception {
File fileMock = Mockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments(Mockito.anyString(), Mockito.anyString()).thenReturn(fileMock);
FolderServiceImpl sut = new FolderServiceImpl sut ();
Mockito.when(fileMock.exists()).thenReturn(true);
sut.getStatus("");
// Your verifications..
}
}
Powermock will mock the File object which is created in the method getStatus of your class. With Mockito.when you can say what is the return value of folderStatusFile.exists() in your code.
EDIT
I have included the following two jars with maven, but you don't need to use maven: https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6 and https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9 and https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19
I am writing a JUnit for a method that uses FileInputStream and in the constructor only the file name is passed. The file is created as part of a servlet request and this file is not stored any where.
I am trying to Mock FileInputStream using PowerMockito so that it gives me a mocked file object. Unfortunately I get FileNotFoundException which is valid but I am not sure how to test this method then because the file doesn't exist.
Method under test:
public String viewReport() throws Exception {
this.inputStream = new FileInputStream(DOCUSIGN_REPORT_FILE);
try {
boolean returnReport = validateRequest();
if (returnReport) {
intgList = this.generateViewIntegrationReportData(getESignUIConfig());
this.createCSVFile(intgList, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return null;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return null;
}
return UiIntegrationKeyConstants.REPORT_REPSONSE;
}
JUnit test so far.
#Test
public void testViewReport() throws Exception {
Map<String, Object> actionMap = new HashMap<>();
actionMap.put("application", "ESignatureIntegrationAction");
ActionContext.setContext(new ActionContext(actionMap));
FileInputStream inputStream = Mockito.mock(FileInputStream.class);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(inputStream);
action = new ESignatureIntegrationAction();
action.viewReport();
}
I get an exception when the code reaches to new FileInputStream(DOCUSIGN_REPORT_FILE);
Thanks for the help.
I would suggest to refactor your code in a way that allows testing without a mocking framework.
It could look somewhat like this:
public class YourClass {
// ...
public String viewReport() {
try {
boolean isValidRequest = validateRequest();
if (isValidRequest) {
IntegrationReportCsvFileHandler fileHandler = new IntegrationReportCsvFileHandler();
IntegrationReportData inputData = fileHandler.readData(new FileInputStream(DOCUSIGN_REPORT_FILE));
IntegrationReportGenerator generator = new IntegrationReportGenerator();
IntegrationReportData outputData = generator.processData(inputData, getESignUIConfig());
fileHandler.writeReport(outputData, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
return UiIntegrationKeyConstants.REPORT_RESPONSE;
}
// ...
}
public class IntegrationReportData {
// your custom data structure
// may as well just be a List<Data>
// may be different for input and output
}
public class IntegrationReportException extends Exception {
// your custom exception
public IntegrationReportException(String message) { super(exception); }
}
public class IntegrationReportGenerator {
public IntegrationReportData processData(IntegrationReportData data, ESignConfig config) throws IntegrationReportException {
// here's your logic that requires testing
}
}
public class IntegrationReportCsvFileHandler {
public IntegrationReportData readData(InputStream input) throws IOException {
// read data from given input stream
}
public void writeData(IntegrationReportData data, OutputStreamWriter outputWriter) throws IOException {
// write data to given output stream
}
}
That way the IntegrationReportGenerator would be easily testable.