I'm trying to write a unit test that checks if methods were invoked in an order. To do that I'm using Mockito's inOrder.verify() like this:
#Test
public void shouldExecuteAllFileCommandsOnAFileInFIFOOrder() {
// Given
ProcessFileListCommand command = new ProcessFileListCommand();
FileCommand fileCommand1 = mock(FileCommand.class, "fileCommand1");
command.addCommand(fileCommand1);
FileCommand fileCommand2 = mock(FileCommand.class, "fileCommand2");
command.addCommand(fileCommand2);
File file = mock(File.class, "file");
File[] fileArray = new File[] { file };
// When
command.executeOn(fileArray);
// Then
InOrder inOrder = Mockito.inOrder(fileCommand1, fileCommand2);
inOrder.verify(fileCommand1).executeOn(file);
inOrder.verify(fileCommand2).executeOn(file);
}
However, the second verify() fails with the following error:
org.mockito.exceptions.verification.VerificationInOrderFailure:
Verification in order failure
Wanted but not invoked:
fileCommand2.executeOn(file);
-> at (...)
Wanted anywhere AFTER following interaction:
fileCommand1.executeOn(file);
-> at (...)
If I change .executeOn(file) to .executeOn(any(File.class)) the test passes, but I want to make sure that the methods are invoked using the same argument.
Here's the class I'm testing:
public class ProcessFileListCommand implements FileListCommand {
private List<FileCommand> commands = new ArrayList<FileCommand>();
public void addCommand(final FileCommand command) {
this.commands.add(command);
}
#Override
public void executeOn(final File[] files) {
for (File file : files) {
for (FileCommand command : commands) {
file = command.executeOn(file);
}
}
}
}
The test fails because the argument to the second executeOn() method call is not the same file as the argument of the first one, since the first file is replaced by another one in
file = command.executeOn(file);
Related
I want to create junit test to see if the content inside a File is added into an arraylist
Here is my function:
public List readContent(final File file, final boolean isFirstFile) throws IOException
{
List<String> lines = new ArrayList<>();
try
{
BufferedReader br = new BufferedReader(new FileReader(file));
String strLine;
if (!isFirstFile)
{
br.readLine();
}
while ((strLine = br.readLine()) != null)
{
lines.add(strLine);
}
}
catch (IOException e)
{
LOG.info("An error occurred while reading file.");
e.printStackTrace();
}
return lines;
}
Thanks in advance.
You can use the JUnit temporary file. It basically creates a file/folder for you during the test and when the test finishes it will be deleted.
To test it you just create that file, put the data you want on it and then call your method. Then you assert result of the method with the value you were expecting.
About the temporary file for JUnit 4: https://howtodoinjava.com/junit/junit-creating-temporary-filefolder-using-temporaryfolder-rule/
In case you using JUnit 5: https://www.baeldung.com/junit-5-temporary-directory
You can use TemporaryFolder to create temporary folders and files and ErrorCollector to assert more one assertion
#RunWith(MockitoJUnitRunner.class)
public class TargetTest {
public TemporaryFolder folder = new TemporaryFolder();
public ErrorCollector collector = new ErrorCollector();
#Rule
public RuleChain chain = RuleChain.outerRule(collector).around(folder);
private TargetClass target;
#Before
public void setUp() {
target = new TargetClass();
}
#Test
public void shouldReadFile() throws Exception {
// Arrange
File file = folder.newFile("myfile.txt");
// Act
List actual = target.readContent(file, true);
// Assert
}
}
You can also simply create a test file (or several depending on what you want to test) that you would store in the src/test/resources folder (if you use Maven/Gradle) and then as part of your test preparation you would load this file and pass it to the method.
How do you mock file reading/writing via JUnit?
Here is my scenario
MyHandler.java
public abstract class MyHandler {
private String path = //..path/to/file/here
public synchronized void writeToFile(String infoText) {
// Some processing
// Writing to File Here
File file = FileUtils.getFile(filepath);
file.createNewFile();
// file can't be written, throw FileWriteException
if (file.canWrite()) {
FileUtils.writeByteArrayToFile(file, infoText.getBytes(Charsets.UTF_8));
} else {
throw new FileWriteException();
}
}
public String readFromFile() {
// Reading from File here
String infoText = "";
File file = new File(path);
// file can't be read, throw FileReadException
if (file.canRead()) {
infoText = FileUtils.readFileToString(file, Charsets.UTF_8);
} else {
throw FileReadException();
}
return infoText
}
}
MyHandlerTest.java
#RunWith(PowerMockRunner.class)
#PrepareForTest({
MyHandler.class
})
public class MyHandlerTest {
private static MyHandler handler = null;
// Some Initialization for JUnit (i.e #Before, #BeforeClass, #After, etc)
#Test(expected = FileWriteException.class)
public void writeFileTest() throws Exception {
handler.writeToFile("Test Write!");
}
#Test(expected = FileReadException.class)
public void readFileTest() throws Exception {
handler.readFromFile();
}
}
Given above source, Scenario when file is not writable (write permission not allowed) is OK, However, when i try to do scenario wherein file is not readable (read permission not allowed). It always read the file, i have already tried to modify the file permission on the test code via below
File f = new File("..path/to/file/here");
f.setReadable(false);
However, I did some reading, setReadable() always returns false (failed) when run on Windows machine.
Is there a way to modify the file permission of the target file programmatically in relation to JUnit?
Note
Target source code to test cannot be modified, meaning
Myhandler.class is a legacy code which is not to be modified.
Instead of relying on the operating system file permissions, use PowerMock to mock FileUtils.getFile(...) and make it return an instance of File (e.g. anonymous sub class) that returns a specific value for canWrite()/canRead().
Mocking static methods with Mockito
Since Mockito cannot mock static methods, use a File factory instead (or refactor your FileUtils to be a factory), then you can mock it and return a mocked File instance as well, where you can also mock any File methods you want.
So instead of FileUtils.getFile(filepath) you will now have something like FileFactory.getInstance().getFile(filepath) for example, where you can mock getFile(String) method easily.
In jUnit there's a handy rule for scenarios like yours.
public class MyHandlerTest {
#Rule
// creates a temp folder that will be removed after each test
public org.junit.rules.TemporaryFolder folder = new org.junit.rules.TemporaryFolder();
private MyHandler handler;
#Before
public void setUp() throws Exception {
File file = folder.newFile("myFile.txt");
// do whatever you need with it - fill with test content and so on.
handler = new MyHandler(file.getAbsolutePath()); // use the real thing
}
// Test whatever behaviour you need with a real file and predefined dataset.
}
I figured out how to use the Ant API to run a JUnit Test and create an XML of the result.
String pathToReports = "/tmp/junitreports";
Project project = new Project();
JUnitTest test = null;
try
{
new File(pathToReports).mkdir();
JUnitTask task = new JUnitTask();
project.setProperty("java.io.tmpdir",pathToReports);
task.setProject(project);
FormatterElement.TypeAttribute type = new FormatterElement.TypeAttribute();
type.setValue("xml");
FormatterElement formater = new FormatterElement();
formater.setType(type);
task.addFormatter(formater);
test = new JUnitTest(TestClass.class.getName());
test.setTodir(new File(pathToReports));
task.addTest(test);
task.execute();
}
...
TestClass:
public class TestClass
{
#Test
public void test()
{
fail("failed");
}
}
The Code works just fine. The XML is created and I can see that the test "failed".
Now my question: is there any way to also get the test results programatically? I expected to get an updated version of the JUnitTest object somehow where I can call the method "failureCount()".
test.failurecount() after execution of the task returns 0 of course. Parsing the XML seems odd to me as the number of failures should already be stored somewhere.
You could have a variable (int failedTests) increment each time a test fails. You could do this by using a TestWatcher rule.
After all the tests have run you could print it out (or do whatever you wanna do with it...) with:
#AfterClass
public static void printFailedTestsCount() {
System.out.println(failedTests + " tests failed.");
}
The following code works when I execute the Pig script locally while specifying a local GeoIPASNum.dat file. However, it does not work when run in MapReduce distributed mode. What am I missing?
Pig job
DEFINE AsnResolver AsnResolver('/hdfs/location/of/GeoIPASNum.dat');
loaded = LOAD 'log_file' Using PigStorage() AS (ip:chararray);
columned = FOREACH loaded GENERATE AsnResolver(ip);
STORE columned INTO 'output/' USING PigStorage();
AsnResolver.java
public class AsnResolver extends EvalFunc<String> {
String ipAsnFile = null;
#Override
public String exec(Tuple input) throws IOException {
try {
LookupService lus = new LookupService(ipAsnFile,
LookupService.GEOIP_MEMORY_CACHE);
return lus.getOrg((String) input.get(0));
} catch (IOException e) {
}
return null;
}
public AsnResolver(String file) {
ipAsnFile = file;
}
...
}
The problem is that you are using a string reference to an HDFS path and the LookupService constructor can't resolve the file. It probably works when you run it locally since the LookupService has no problem with a file in your local FS.
Override the getCacheFiles method:
#Override
public List<String> getCacheFiles() {
List<String> list = new ArrayList<String>(1);
list.add(ipAsnFile + "#GeoIPASNum.dat");
return list;
}
Then change your LookupService constructor to use the Distributed Cache reference to "GeoIPASNum.dat" :
LookupService lus = new LookupService("GeoIPASNum.dat", LookupService.GEOIP_MEMORY_CACHE);
Search for "Distributed Cache" in this page of the Pig docs: http://pig.apache.org/docs/r0.11.0/udf.html
The example it shows using the getCacheFiles() method should ensure that the file is accessible to all the nodes in the cluster.
I wrote unit test (JUnit 4) that performs some logic and writes result to file. In #Before annotated method it creates file and in #After the file should be deleted. It isn't though, and I can't figure it out, why.
I am using Google Guava 10.01 Files API. Here's my unit test code:
public class CashierTest extends ContextedTest {
private File cashierFile;
#Before
public void createFile() throws Exception {
cashierFile = new File("D://workspace-sts/spring-miso/cashier.txt");
cashierFile.createNewFile();
}
#After
public void release() {
if (cashierFile.exists()) {
if (!cashierFile.delete()) {
System.out.println("Couldn't delete cashier file");
}
}
cashierFile = null;
}
#Test
public void testCashier() throws Exception {
// file shouldn't contain any text
assertFalse(Files.toString(cashierFile, Charset.defaultCharset()).length() > 0);
Cashier cashier = (Cashier) context.getBean("cashier");
ShoppingCart cart = (ShoppingCart) context.getBean("shoppingCartPrototype");
cashier.checkout(cart);
assertTrue(cashierFile.exists());
// file should contain text now
assertTrue(Files.toString(cashierFile, Charset.defaultCharset()).length() > 0);
}
#Override
protected void setPath() {
path = "sk/xorty/advancedioc/beans.xml";
}
}
Note: ContextedTest superclass is my test which holds Spring container it isn't relevant atm.
Simply instanting a File does not mean that an actual file will be created. Call createNewFile() or createTempFile() on that instance for this.
Within your test method you don't seem to pass that file reference to anyone that could possibly create the file or write anything in it... Am I missing something or is the code you posted missing some key lines ?
You should use the TemporaryFolder Rule with JUnit 4. This will handle the setup and teardown of temporary test directories and files.
public static class HasTempFolder {
#Rule public TemporaryFolder folder= new TemporaryFolder();
#Test public void testUsingTempFolder() throws IOException {
File createdFile= folder.newFile("myfile.txt");
...
}
}
Other Rules are part also part of Junit 4.