Junit Testing Mocking a File Operation - java

I have a piece of code similar to the below that I have been asked to Junit test. We are using Junit, EasyMock and Spring Framework. I've not done much Junit testing, and am a bit lost as to how I can mock the below.
Basically the path to the file as in the directory it will be in, won't exist when I'm writing or running the test on my machine. I'm wondering is there a way to mock the object to a temporary location as the location it will actually run with is guaranteed to exist and be tested during integration testing.
However I'm wondering would it even be wise to do so or should this be tested when it is integrated with the rest of the project when the directory will actually exist.
Any help appreciated, as Junit testing is completely new to me. I've looked around but can't see how to do what I want (might be a good hint that I shouldn't be doing it :P).
String fileName = pathToFileName;
File file = new File(fileName);
if (file.exists()) {
FileUtil.removeLineFromFile(file, getValueToRemove(serialNumber));
}

First option is to inject the file into your class where you can just inject the mock directly. Usually the better option, but not always elegant or feasible.
I've gotten some mileage out of these things by creating a protected wrapper function for problematic objects such as this. In your class under test:
protected File OpenFile(String fileName) { return new File(filename;}
In the test class:
File file = EasyMock.createNiceMock(File.class);
private MyClass createMyClass() {
return new MyClass() {
#Override protected File OpenFile(String fileName) { return file; }
};
}
#Test public testFoo() {
EasyMock.expect(file.exists()).andStubReturn(true);
//...
MyClass myClass=createMyClass();
// ...
}
If you need, you can save off the construction parameters (fileName) in this case for validation.

Related

Test and Runtime getting data from different sources

I have a Spring application which gets data from an API. We test over Jenkins and the problem is that Jenkins doesn't have access to this API.
So our solution is to embedded some sample files with these API endpoints, to src/test/resources.
But the code is becoming a mess since I don't know how to differ if it's testing or running.
For example:
private void loadDataFromEndpointOne(boolean isTest) {
List<String> someData = new ArrayList<>();
if (isTest) {
ClassLoader loader = this.getClass().getClassLoader();
String file = loader.getResource("endpointOne.txt");
...
someData = someMethodReadingResourceFile();
}
else {
someData = someMethodReadingFromAPI();
}
}
So, from JUnit #Test I set isTest as true and from runtime false.
This does not sound elegant to me.
Is there a clever way?
If you are writing JUnit test its better to use Mockito or PowerMockito (or any other librbrary for that matter) to mock the API call. Thats the cleaner way of doing JUnit tests.
For example if you have :
private void loadDataFromEndpointOne() {
someData = someMethodReadingFromAPI();
}
Mock it like this from your test class :
Mockito.when(mockedClass.loadDataFromEndpointOne()).thenReturn(someDummyDataForTest);
For more info you can refer Mockito's doc.

How can I write valid JUnit tests when mocking a filepath?

I am trying to write some JUnit tests for a set of methods which use some REST services on the web.
In general, within my methods, I am providing a filepath and a configuration as a parameter, but I expect things will get more complicated as I progress.
For right now, what are the best ways for me to write JUnit tests for the likes of :
public Answers changeFileToAnswer(String filePath, String mediaType) {
File document = new File(filePath);
Answers answers = restService.changeFileToAnswer(document, mediaType);
return answers;
}
What kind of Unit tests can I write for a simple class like this? Testing the answers object would be an integration tests, since an external call is made here, right? What is good practise here? Is there a way to mock the filepath being passed in as a parameter?
Notes -
This method is from a REST interface which will later be exposed through a GUI. I am currently testing it with POST calls from POSTman. Due to this, I am passing in a string for the filePath rather than a file object (as I could not post this to my server).
Thanks.
The test is not necessary to be integration. Your restService need to be mock or fake, so there is no real external call.
For mocking filePath you can use JUnit TemporaryFolder.
public class TestClass{
#Rule
private TemporaryFolder folder = new TemporaryFolder();
#Test
public void testMethod(){
File tempFile = folder.newFile("myfile.txt");
classUnderTest.changeFileToAnswer(file.getPath(), mediaType);
}
}
This rule will create a real file in file system which will be removed when tests finish execution.
UPD: You might also want to take a look at jimfs

Unit testing file write in Java without interface wrappers

I have an existing Java class that writes to a file.
public final class WriteToFile{
private Writer file_writer;
private static final String encoding_format = "UTF8";
private FileWrite(final File fpath) throws IOException {
this.file_writer = new OutputStreamWriter(new FileOutputStream(fpath), encoding_format);
}
#Override
public void fileWrite(final String msg) {
try {
this.file_writer.write(msg);
this.file_writer.write("\n");
this.file_writer.flush();
this.file_writer.close();
} catch (IOException e) {
log.error("File write failed", e);
}
}
}
In order to unit test this, I learnt that creating a file mock using a Mocking framework is not a good practice . What do I test here? The only way of testing this is to probably do the file write again, and check if the expected contents and actual contents are the same. In that case, doing it the JUnit way would be as mentioned in this post How to test write to file in Java?. However, I am not going to rewrite the file writing code, to include interface wrappers. How do I go about with this?
#Test public void testfileWrite() {
String msg = "somemessage";
String fpath = "path/to/file";
Writer file_writer = new OutputStreamWriter(new FileOutputStream(fpath), "UTF8");
file_writer.write(msg);
assertEquals("somemessage", file_writer.toString());
}
Is this all that needs to be tested?
The point of this class is to write a file. It does nothing else (and that is a good thing). So don't bother with a mockist unit test, all it shows is that you can write a ton of mock code. Instead write a Integration Test.
Use the JUnit rule TemporaryFolder to create and destroy a folder to put your test file in, then verify the file has what you want in it at the end of the test. The only time you should consider mocking for this kind of test is if the exceptional case does something funky. Then you can either do some evil black magic involving Powermock or pass in some form of "File Stream factory". Or ask yourself if that is really such a great place for complex logic that needs testing, and then move it.
When testing classes that make use of WriteToFile, mock or stub WriteToFile.
When it comes to write unit tests that must check generated files, I always prepare myself a repository of cases: For each case, an input file (if necessary), and and a set of expected output files.
I write one test method for each case, where I call the business logic, which will generate one (or some) file into the working directory, and I eventually check if the generated file is equal to the proper expected file.
I prepare the expected files manually and check them in into the Source Control System, so that they belong to each released version. If, in future, the business logic must change its behaviour, then it is required that the expected file be changed accordingly, and that both the code and the file be checked in and tagged together in the same release.
That is the easiest and safest way I found for checking generated files.
Use Powermockito to mock the call to the constructor of FileOutputStream and OutputStreamWriter as in: http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/
Then verify that file_writer methods write(String) and flush() have been invoked twice and once, respectively; and at the end close().

How do I create pre-formatted Java files in Eclipse?

I am currently writing JUnit test cases using the Selenium-RC API. I am writing my scripts like:
//example JUnit test case
public class myScripts extends SeleneseTestCase {
public void setUp() throws Exception {
SeleniumServer newSelServ = new SeleniumServer();
newSelServ.start();
setUp("https://mySite.com", "*firefox");
}
public void insert_Test_Name throws Exception {
//write test code here
}
}
And for each test, I have a new JUnit file. Now, since the beginning of my JUnit files will all basically be the same, just with minor variations towards the end, I was thinking about creating a pre-formatted Java template to write create a file with the redundant code already written. However, I can't find any information on whether this is possible. Does Eclipse allow you to create file templates for certain packages?
Create a super class to add all the common code. Creating template is really bad because of the fact you are duplicating the code at the end of the day.
class Super extends SeleneseTestCase{
// Add all common code
}
class Test1 extends Super{
// only special test case logic
}
Also I would suggest not to create SeleniumServer instance for each test case, It will reduce overall performance of the test suite. You can reuse object as long as you are running test sequentially.

Mockito - Mocking behaviour of a File

I have a class that takes in a single file, finds the file related to it, and opens it. Something along the lines of
class DummyFileClass
{
private File fileOne;
private File fileTwo;
public DummyFileClass(File fileOne)
{
this.fileOne = fileOne;
fileTwo = findRelatedFile(fileOne)
}
public void someMethod()
{
// Do something with files one and two
}
}
In my unit test, I want to be able to to test someMethod() without having to have physical files sitting somewhere. I can mock fileOne, and pass it to the constructor, but since fileTwo is being calculated in the constructor, I don't have control of this.
I could mock the method findRelatedFile() - but is this the best practice? Looking for the best design rather than a pragmatic workaround here. I'm fairly new to mocking frameworks.
In this sort of situation, I would use physical files for testing the component and not rely on a mocking framework. As fge mentions it may be easier plus you don't have to worry about any incorrect assumptions you may make of your mock.
For instance, if you rely upon File#listFiles() you may have your mock return a fixed list of Files, however, the order they are returned in is not guaranteed - a fact you may only discover when you run your code on a different platform.
I would consider using JUnit's TemporaryFolder rule to help you set up the file and directory structure you need for your test, e.g.:
public class DummyFileClassTest {
#Rule
public TemporaryFolder folder = new TemporaryFolder();
#Test
public void someMethod() {
// given
final File file1 = folder.newFile("myfile1.txt");
final File file2 = folder.newFile("myfile2.txt");
... etc...
}
}
The rule should clean up any created files and directories when the test completes.

Categories

Resources