Grails spock Testing with File class - unit-testing

I have a method that create a file based in a content copied from an another file.
Like below
private cloneBaseFile(fileName, ddi, ddd){
def config = grailsApplication.config.kicksim.fileConstants
String baseFileContents = new File(config.baseFile).getText('UTF-8')
def help = handleString("${ddd}.${ddi}")
baseFileContents = baseFileContents.replaceAll("DDDDDI", help);
def f1= new File(fileName)
f1 << baseFileContents
return fileName
}
I'd like to know how to unit test it.

I think you should look to separate out the responsibilities of this method (c.f. Single Responsibility Principle). If you haven't got a copy of Robert Martin's book called Clean Code then I'd highly recommend it: his code is a work of art and taught me a lot.
cloneBaseFile() is actually doing many things: it's opening a file, getting the contents of the file, doing something (I don't know what) in handleString(), replacing the contents of the file with a modified version of its contents and then finally saving the file.
How about (as a starter for 10):
private cloneBaseFile(fileName, ddi, ddd){
def config = grailsApplication.config.kicksim.fileConstants
String baseFileContents = getFileContents(config.baseFile)
baseFileContents = handleFileContents(baseFileContents)
return createNewFileWithContents(fileName, baseFileContents)
}
String getFileContents(String fileName) {
String contents = new File(fileName).getText('UTF-8')
return contents
}
String handleFileContents(String oldContents) {
def help = handleString("${ddd}.${ddi}")
return oldContents.replaceAll("DDDDDI", help);
}
String createNewFileWithContents(String newFileName, String newContents) {
def f1= new File(newFileName)
f1 << newContents
return newFileName
}
Now you have multiple small methods, each of which can be tested far more easily. You'll also want to test the handleString() method.

Related

How do I test test these file i/o methods using Mock()? Using groovy & spock

I'm having trouble reading other Stack Overflow posts so after a few hours I'm looking for help.
I have two methods that I want to test. And I'd like to test the second one using Mock, but having trouble figuring out what to do.
Here's the first method:
String readFileContents(Path filePath) {
StringBuilder fileContents = new StringBuilder()
BufferedReader br = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)
String line
while ((line = br.readLine()) != null) {
fileContents.append(line).append('\n')
}
fileContents
}
And I test it with
class CdmFileSpec extends Specification {
private CdmFile cdmFile
private static final String filePath = 'src/test/resources/cdm/test/cdmFileTestFile.txt'
void setup() {
cdmFile = new CdmFile()
}
void 'test noFileExists'() {
given:
Path notRealPath = Paths.get('src/test/resources/cdm//test/notreal.txt')
when:
String fileContents = cdmFile.readFileContents(notRealPath)
then:
thrown NoSuchFileException
}
void 'test readFileContents() reads file contents'() {
given:
Path testFilePath = Paths.get(filePath)
when:
String fileContents = cdmFile.readFileContents(testFilePath)
then:
fileContents.contains('hip hop horrayy\n\nhoooo\n\nheyyy\n\nhoooo')
}
}
This works as I've placed a real file in the filePath.
I'm wondering... how can I test the next method using Mock?
void eachLineInFileAsString(Path filePath,
#ClosureParams(value = SimpleType, options = ['java.lang.String'] )Closure applyLine) {
BufferedReader br = Files.newBufferedReader(filePath)
String line
while ((line = br.readLine()) != null) {
applyLine.call(line)
}
}
The problem with mocking in so many cases is that methods create their own dependencies instead of having them injected or calling a mockable service method creating them. I suggest you refactor your code just a little bit, extracting BufferedReader creation into a service method:
package de.scrum_master.stackoverflow.q56772468
import groovy.transform.stc.ClosureParams
import groovy.transform.stc.SimpleType
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
class CdmFile {
String readFileContents(Path filePath) {
StringBuilder fileContents = new StringBuilder()
BufferedReader br = createBufferedReader(filePath)
String line
while ((line = br.readLine()) != null) {
fileContents.append(line).append('\n')
}
fileContents
}
void eachLineInFileAsString(
Path filePath,
#ClosureParams(value = SimpleType, options = ['java.lang.String']) Closure applyLine
) {
BufferedReader br = createBufferedReader(filePath)
String line
while ((line = br.readLine()) != null) {
applyLine.call(line)
}
}
protected BufferedReader createBufferedReader(Path filePath) {
Files.newBufferedReader(filePath, StandardCharsets.UTF_8)
}
}
Now mocking is quite simple and you don't even need your test resource file anymore (only if you want to do an integration test without mocks):
package de.scrum_master.stackoverflow.q56772468
import spock.lang.Specification
import java.nio.charset.StandardCharsets
import java.nio.file.NoSuchFileException
import java.nio.file.Path
import java.nio.file.Paths
class CmdFileTest extends Specification {
private static final String filePath = 'mock/cdmTestFile.txt'
private static final String fileContent = """
I heard, that you're settled down
That you found a girl and you're, married now
I heard, that your dreams came true
I guess she gave you things
I didn't give to you
""".stripIndent()
private CdmFile cdmFile
void setup() {
cdmFile = Spy() {
createBufferedReader(Paths.get(filePath)) >> {
new BufferedReader(
new InputStreamReader(
new ByteArrayInputStream(
fileContent.getBytes(StandardCharsets.UTF_8)
)
)
)
}
}
}
def "non-existent file leads to exception"() {
given:
Path notRealPath = Paths.get('notreal.txt')
when:
cdmFile.readFileContents(notRealPath)
then:
thrown NoSuchFileException
}
def "read file contents into a string"() {
given:
Path testFilePath = Paths.get(filePath)
when:
String fileContents = cdmFile.readFileContents(testFilePath)
then:
fileContents.contains("your dreams came true\nI guess")
}
def "handle file content line by line"() {
given:
def result = []
def closure = { line -> result << line }
Path testFilePath = Paths.get(filePath)
when:
cdmFile.eachLineInFileAsString(testFilePath, closure)
then:
result == fileContent.split("\n")
}
}
Please note that I am using a Spy() here, i.e. leaving the original CdmFile object intact and just stubbing the service method createBufferedReader(..) when called with exactly parameter Paths.get(filePath). For other paths the original method is called, which is important for the non-existent file test or if you want to add tests involving real resource file loading like in your own example.
Whenever it is difficult to test a class or component, difficult to inject mocks or otherwise isolate the subject under test, that is a reason to refactor your application code for better testability. When done right also it should also result in better separation of concerns and better componentisation. If your tests become very sophisticated, contrived, brittle and hard to understand and maintain, that is usually a smell and you ought to refactor the application code instead.
There's no need for a Mock, as you can just use a locally defined Closure:
def "test the method"() {
given:
def result = []
def closure = { line -> result << line }
Path testFilePath = Paths.get(filePath)
when:
eachLineInFileAsString(testFilePath, closure)
then: // I'm guessing here
result == [
'line 1',
'line 2',
'line 3',
'line 4'
]
}

Java: return a LinkedHashSet

Basically, I'm trying to return a collection of strings in Java.
But...
each string must be unique because they're all the names of ".db" files in current folder, so I thought this collection should be LinkedHashSet.
The elements (filenames) must maintain the exact same order, so I can choose one of them by it's order number in the collection.
My main routine will show this collection in a GUI component (maybe a JList) for the user to choose one of them (without the .db extension).
I'm totally newbie (as you can see), so if you think there are better options than LinkedHashSet please tell me.
Also, how can I grab this collection in the main class?
What I've got so far:
public Set GetDBFilesList() {
//returns ORDERED collection of UNIQUE strings with db filenames
LinkedHashSet a = new LinkedHashSet();
FilenameFilter dbFilter = (File file, String name) -> {
return name.toLowerCase().endsWith(".db");
};
String dirPath = "";
File dir = new File(dirPath);
File[] files = dir.listFiles(dbFilter);
if (files.length > 0) {
for (File aFile : files) {
a.add(aFile.getName());
}
}
return a;
}
You want an ordered and unique collection - LinkedHashSet is a good choice.
Some comments on your methode:
Your should use Generics f.e.: LinkedHashSet<File> or LinkedHashSet<String>
The check for files.length is unnecessary, but you could check for null if the path is not a directory or an I/O error occured
You should name your variables properly: a is not a good name
Your methode can be static - maybe in a static helper class?
The Set.add methode returns true or false if the item was added or not, you should check that just in case
Putting all together:
//Your Main class
public class Main
{
public static void main(String[] args)
{
File dir = new File("");
Collection<File> dbFiles = DbFileManager.getDatabaseFiles(dir);
}
}
//Your DB File Reader Logic
public class DbFileManager
{
public static Collection<File> getDatabaseFiles(File directory)
{
Collection<File> dbFiles = new LinkedHashSet<>();
//filter code etc.
boolean success = dbFiles.addAll(directory.listFiles(filter));
//Check if everthing was added
return dbFiles;
}
}

grails spock test mock CommonsMultipartFile

I've following old method written in code, which is for accessing request object in service class such as:
def someServiceMethod() {
....
def webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest) request
CommonsMultipartFile file = (CommonsMultipartFile) mpr.getFile("file")
....
}
This is my unit test code for serivce class.
#TestFor(SomeService)
class SomeServiceSpec extends Specification {
void "test someServiceMethod"() {
given:
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest()
FileInputStream inFile = new FileInputStream("./test-data/Hiearchy-003.xlsx") //valid file path
def multipartFile = new GrailsMockMultipartFile('file', 'file.xls', 'multipart/form-data', inFile)
request.addFile(multipartFile)
GrailsWebRequest webRequest = new GrailsWebRequest(
request,
new MockHttpServletResponse(),
new MockServletContext()
)
request.setAttribute(GrailsApplicationAttributes.WEB_REQUEST,webRequest)
RequestContextHolder.setRequestAttributes(webRequest);
when:
def result = service.someServiceMethod()
then:
result != null
//some more assertions
//..
}
}
I'm stuck with following error.
| Failure: test someServiceMethod(SomeServiceSpec)
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile#6ae8e5dd' with class 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile' to class 'org.springframework.web.multipart.commons.CommonsMultipartFile'
Anybody faced such issue before in grails unit test?
Instead of : GrailsMockMultipartFile,
use: org.springframework.mock.web.MockMultipartFile.
I just realised following line is just unnecessary if we use input stream direct it should not be problem hence solved my issue..
CommonsMultipartFile file = (CommonsMultipartFile) mpr.getFile("file")

GATE Embedded runtime

I want to use "GATE" through web. Then I decide to create a SOAP web service in java with help of GATE Embedded.
But for the same document and saved Pipeline, I have a different run-time duration, when GATE Embedded runs as a java web service.
The same code has a constant run-time when it runs as a Java Application project.
In the web service, the run-time will be increasing after each execution until I get a Timeout error.
Does any one have this kind of experience?
This is my Code:
#WebService(serviceName = "GateWS")
public class GateWS {
#WebMethod(operationName = "gateengineapi")
public String gateengineapi(#WebParam(name = "PipelineNumber") String PipelineNumber, #WebParam(name = "Documents") String Docs) throws Exception {
try {
System.setProperty("gate.home", "C:\\GATE\\");
System.setProperty("shell.path", "C:\\cygwin2\\bin\\sh.exe");
Gate.init();
File GateHome = Gate.getGateHome();
File FrenchGapp = new File(GateHome, PipelineNumber);
CorpusController FrenchController;
FrenchController = (CorpusController) PersistenceManager.loadObjectFromFile(FrenchGapp);
Corpus corpus = Factory.newCorpus("BatchProcessApp Corpus");
FrenchController.setCorpus(corpus);
File docFile = new File(GateHome, Docs);
Document doc = Factory.newDocument(docFile.toURL(), "utf-8");
corpus.add(doc);
FrenchController.execute();
String docXMLString = null;
docXMLString = doc.toXml();
String outputFileName = doc.getName() + ".out.xml";
File outputFile = new File(docFile.getParentFile(), outputFileName);
FileOutputStream fos = new FileOutputStream(outputFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
OutputStreamWriter out;
out = new OutputStreamWriter(bos, "utf-8");
out.write(docXMLString);
out.close();
gate.Factory.deleteResource(doc);
return outputFileName;
} catch (Exception ex) {
return "ERROR: -> " + ex.getMessage();
}
}
}
I really appreciate any help you can provide.
The problem is that you're loading a new instance of the pipeline for every request, but then not freeing it again at the end of the request. GATE maintains a list internally of every PR/LR/controller that is loaded, so anything you load with Factory.createResource or PersistenceManager.loadObjectFrom... must be freed using Factory.deleteResource once it is no longer needed, typically using a try-finally:
FrenchController = (CorpusController) PersistenceManager.loadObjectFromFile(FrenchGapp);
try {
// ...
} finally {
Factory.deleteResource(FrenchController);
}
But...
Rather than loading a new instance of the pipeline every time, I would strongly recommend you explore a more efficient approach to load a smaller number of instances of the pipeline but keep them in memory to serve multiple requests. There is a fully worked-through example of this technique in the training materials on the GATE wiki, in particular module number 8 (track 2 Thursday).

Need the Groovy way to do partial file substitutions

I have a file that I need to modify. The part I need to modify (not the entire file), is similar to the properties shown below. The problem is that I only need to replace part of the "value", the "ConfigurablePart" if you will. I receive this file so can not control it's format.
alpha.beta.gamma.1 = constantPart1ConfigurablePart1
alpha.beta.gamma.2 = constantPart2ConfigurablePart2
alpha.beta.gamma.3 = constantPart3ConfigurablePart3
I made this work this way, though I know it is really bad!
def updateFile(String pattern, String updatedValue) {
def myFile = new File(".", "inputs/fileInherited.txt")
StringBuffer updatedFileText = new StringBuffer()
def ls = System.getProperty('line.separator')
myFile.eachLine{ line ->
def regex = Pattern.compile(/$pattern/)
def m = (line =~ regex)
if (m.matches()) {
def buf = new StringBuffer(line)
buf.replace(m.start(1), m.end(1), updatedValue)
line = buf.toString()
}
println line
updatedFileText.append(line).append(ls)
}
myFile.write(updatedFileText.toString())
}
The passed in pattern is required to contain a group that is substituted in the StringBuffer. Does anyone know how this should really be done in Groovy?
EDIT -- to define the expected output
The file that contains the example lines needs to be updated such that the "ConfigurablePart" of each line is replaced with the updated text provided. For my ugly solution, I would need to call the method 3 times, once to replace ConfigurablePart1, once for ConfigurablePart2, and finally for ConfigurablePart3. There is likely a better approach to this too!!!
*UPDATED -- Answer that did what I really needed *
In case others ever hit a similar issue, the groovy code improvements I asked about are best reflected in the accepted answer. However, for my problem that did not quite solve my issues. As I needed to substitute only a portion of the matched lines, I needed to use back-references and groups. The only way I could make this work was to define a three-part regEx like:
(.*)(matchThisPart)(.*)
Once that was done, I was able to use:
it.replaceAdd(~/$pattern/, "\$1$replacement\$3")
Thanks to both replies - each helped me out a lot!
It can be made more verbose with the use of closure as args. Here is how this can be done:
//abc.txt
abc.item.1 = someDummyItem1
abc.item.2 = someDummyItem2
abc.item.3 = someDummyItem3
alpha.beta.gamma.1 = constantPart1ConfigurablePart1
alpha.beta.gamma.2 = constantPart2ConfigurablePart2
alpha.beta.gamma.3 = constantPart3ConfigurablePart3
abc.item.4 = someDummyItem4
abc.item.5 = someDummyItem5
abc.item.6 = someDummyItem6
Groovy Code:-
//Replace the pattern in file and write to file sequentially.
def replacePatternInFile(file, Closure replaceText) {
file.write(replaceText(file.text))
}
def file = new File('abc.txt')
def patternToFind = ~/ConfigurablePart/
def patternToReplace = 'NewItem'
//Call the method
replacePatternInFile(file){
it.replaceAll(patternToFind, patternToReplace)
}
println file.getText()
//Prints:
abc.item.1 = someDummyItem1
abc.item.2 = someDummyItem2
abc.item.3 = someDummyItem3
alpha.beta.gamma.1 = constantPart1NewItem1
alpha.beta.gamma.2 = constantPart2NewItem2
alpha.beta.gamma.3 = constantPart3NewItem3
abc.item.4 = someDummyItem4
abc.item.5 = someDummyItem5
abc.item.6 = someDummyItem6
Confirm file abc.txt. I have not used the method updateFile() as done by you, but you can very well parameterize as below:-
def updateFile(file, patternToFind, patternToReplace){
replacePatternInFile(file){
it.replaceAll(patternToFind, patternToReplace)
}
}
For a quick answer I'd just go this route:
patterns = [pattern1 : constantPart1ConfigurablePart1,
pattern2 : constantPart2ConfigurablePart2,
pattern3 : constantPart3ConfigurablePart3]
def myFile = new File(".", "inputs/fileInherited.txt")
StringBuffer updatedFileText = new StringBuffer()
def ls = System.getProperty('line.separator')
myFile.eachLine{ line ->
patterns.each { pattern, replacement ->
line = line.replaceAll(pattern, replacement)
}
println line
updatedFileText.append(line).append(ls)
}
myFile.write(updatedFileText.toString())