Unit: How to write test case using jUnit and Mockito - java

I am very new to Mockito and jUnit and TDD in general and I try to learn the right way to do TDD. I need couples of example to kick start my brain. SO please help me
So I have a method getNameInc(String dirPath, String filenName). So given a fileName like bankAccount.pdf, and if in this folder, no file name bankAccount.pdf, then return bankAccountAA.pdf. If there is exist one bankAccount.pdf then return bankAccountBB.pdf The increment is AA-ZZ. When it reach ZZ then it roll back to AA. I already implement the logic of this method. How do I unit test this method using Mockiti and jUnit?
EDIT
Here is the class and methods that are involved.
public class PProcessor{
private final Map<Integer, String> incMap = new HashMap<Integer, String>();
private String getNameInc(String dirPath, String filenName){
String[] nameList = new File(dirPath).list(new FilenameFilter(){
public boolean accept(File file, String name) {
//only load pdf files
return (name.toLowerCase().endsWith(".pdf"));
}
});
//Return the number of occurance that a given file name appear
//inside the output folder.
int freq = 0;
for(int i=0; i<nameList.length; i++){
if(fileName.equals(nameList[i].substring(0, 8))){
freq++;
}
}
return incMap.get(freq);
}
private void generateIncHashMap(){
incMap.put(new Integer(0), "AA");
incMap.put(new Integer(1), "BB");
incMap.put(new Integer(2), "CC");
...
}
}
generateIncHashMap() will be called in the constructor to pre-generate the hash map

You are trying to test your getNameInc(..) method, I assume. When you call it, it looks for the files in the directory you specify, and based on what it finds, decorates the name you gave it.
To make the class unit-testable, you should abstract the dependency on the file system, so that in a mock, you can simulate whatever directory contents you want. Your class will accept an instance of this interface as a dependency, and call it to find out what's in the directory. When you use the class in your program for real, you will supply an implementation of this interface that delegates to the JDK filesystem calls. When you unit-test the class, you will supply Mockito mocks of this interface.
Avoid putting too much logic into the FilesystemImpl class, since you can't write a strict unit test for it. Keep it a very simple wrapper around the filesystem, so that all the intelligent stuff is in Yourclass, which you will write plenty of unit tests for.
public interface Filesystem {
boolean contains(String dirpath, String filename);
}
public class FilesystemImpl {
boolean contains(String dirpath, String filename) {
// Make JDK calls to determine if the specified directory has the file.
return ...
}
}
public class Yourmainclass {
public static void main(String[] args) {
Filesystem f = new FilesystemImpl();
Yourclass worker = new Yourclass(f);
// do something with your worker
// etc...
}
}
public class Yourclass {
private Filesystem filesystem;
public Yourclass(Filesystem filesystem) {
this.filesystem = filesystem;
}
String getNameInc(String dirpath, String filename) {
...
if (filesystem.contains(dirpath, filename) {
...
}
}
}
public class YourclassTest {
#Test
public void testShouldAppendAAWhenFileExists() {
Filesystem filesystem = Mockito.mock(Filesystem.class);
when(filesystem.contains("/some/mock/path", "bankAccount.pdf").thenReturn(true);
Yourclass worker = new Yourclass(filesystem);
String actual = worker.getNameInc("/some/mock/path", "bankAccount.pdf");
assertEquals("bankAccountAA.pdf", actual);
}
#Test
public void testShouldNotAppendWhenFileDoesNotExist {
Filesystem filesystem = Mockito.mock(Filesystem.class);
when(filesystem.contains("/some/mock/path", "bankAccount.pdf").thenReturn(false);
Yourclass worker = new Yourclass(filesystem);
String actual = worker.getNameInc("/some/mock/path", "bankAccount.pdf");
assertequals("bankAccount.pdf", actual);
}
}
Since there's a lot of duplication between the tests, you'd probably create a setup method and do some of the work there, and create some instance variables for the tests to use:
private static final String TEST_PATH = "/some/mock/path";
private static final String TEST_FILENAME = "bankAccount.pdf";
private Filesystem filesystem;
private Yourclass worker;
#Before
public void setUp() {
filesystem = Mockito.mock(Filesystem.class);
worker = new Yourclass(filesystem);
}
#Test
public void testShouldAppendAAWhenFileExists() {
when(filesystem.contains(TEST_PATH, TEST_FILENAME).thenReturn(true);
String actual = worker.getNameInc(TEST_PATH, TEST_FILENAME);
assertEquals("bankAccountAA.pdf", actual);
}
etc...

For what you have described there I wouldn't bother with Mockito, there doesn't seem to be anything to mock (because it is easy to manipulate the file system).
I would test ...
- What happens if I call getNameInc and there are no matching files already
- What happens if I call getNameInc and there are files AA-YY there already
- What happens if I call getNameInc and file ZZ is there already
The point of TDD though is that you should have already written these tests and then implemented your code to make the tests pass. So you won't really be doing TDD since you already have the code.

Related

Unit test existence of a directory - Junit

I have a function that I use to detect whether a certain directory path exists. Here's the function:
public boolean isRunningOnSandbox() {
return Files.isDirectory(Paths.get("/mySandbox/cloud/sandbox"));
}
As you can see, it relies on static method isDirectory. In my team, we do not use PowerMock for testing.
So, how can I test this method? I have tried writing a test like:
#Rule
public TemporaryFolder temporaryFolder;
#Test
public void test() throws IOException {
File parent = new File("/");
temporaryFolder = new TemporaryFolder(parent);
temporaryFolder.create();
File folder = temporaryFolder.newFolder("mySandbox", "cloud", "sandbox");
subject.isRunningOnSandbox();
}
But, I get an error
ava.io.IOException: Permission denied
because it doesn't let me create a temporary folder under the root. I am guessing there is a better way to test this code instead of trying to create a folder.
There are many ways to do it, onee of them migh be like the below one.
Assumming that isRunningOnSandbox method is in some class SomeClass, then refactor this class in this way:
public class SomeClass {
public boolean isRunningOnSandbox() {
return Files.isDirectory(Paths.get(getSanboxPath()));
}
protected String getSanboxPath(){
return "/mySandbox/cloud/sandbox";
}
}
and then in your tests inject into this class another directory to which you have access, for example:
public class SomeClassTest {
class SomeClassToTest extends SomeClass{
String folder;
public SomeClassToTest(String folder){
this.folder = folder;
}
#Override
protected String getSanboxPath(){
return folder;
}
}
static String sandboxFolder = "myTestSandobxFolder";
static Path tempDir;
#BeforeClass
public static void createFolder() throws IOException {
tempDir = Files.createTempDirectory(sandboxFolder);
}
#AfterClass
public static void deleteFolder() throws IOException {
Files.delete(tempDir);
}
#Test
public void IsRunningOnSandbox_shouldReturnTrueWhenPathExists() throws IOException {
//given
SomeClass testedObject = new SomeClassToTest(tempDir.toString());
//when
boolean result = testedObject.isRunningOnSandbox();
//then
assertThat(result).isTrue();
}
#Test
public void IsRunningOnSandbox_shouldReturnFalseWhenPathDoesNotExist() throws IOException {
//given
SomeClass testedObject = new SomeClassToTest("/abcdef123");
//when
boolean result = testedObject.isRunningOnSandbox();
//then
assertThat(result).isFalse();
}
}
The function you have shown is not suited for unit-testing: With unit-testing you try to find the bugs in small, isolated software pieces. But, which bugs could be in this example code that are not related to the other components, that is, the Files component, the Paths component and the actual file system?
The potential bugs in your example are about questions like "am I calling the right functions?" or "do I call the functions with proper values for the arguments?" or "do the functions I call return arguments as I expect" or "am I using the path that is also the path found in the file system". This can not be checked with unit-testing, but with integraton-testing.
Imagine you have the wrong path in mind. Then, in your unit-test you would also check against the same wrong path, and your unit-test would succeed. Only when running that test as an integration test on the real file system you could figure out that the path which you had in mind was wrong and did not match the actual path in the file system.

How to test File.delete() function in Junit

I have one method like below:
public final class someTask {
public void sampleMethod(String filePath) {
//It is calling Files.delete() method.
Files.delete(new File(filePath).toPath)
}
}
When I test above method(for example ValidRecord in that file, Valid file parameter or not etc) test cases, most of the time my test case failed. Please some one can help me how to test for above cases.
To get file I am using below snippet
#Mock
File fileMock;
#Rule
ExpectedException exception = ExpectedException.none();
PowerMockito.whenNew(File.class).withArguments(VALID_Path).thenReturn(fileMock);
PowerMockito.when(fileMock.exists()).thenReturn(true);
PowerMockito.when(fileMock.isFile()).thenReturn(true);
In this, I am not planning to test Files.deplete() method but I am planning test behaviour of my own method. In that process every time I am getting "java.nio.file.NoSuchFileException" exception even I create temporary file.
Please some can provide with example, how to test this.
One might argue that your approach is wrong by verifying the behaviour through mocking and interactions. I would do the following
Create a temp file on local file system
Call the method sampleMethod
Verify that the file doesn't exist anymore.
A valuable approach to such kinds of question is to go one step back criticize your application design. Ask yourself, whether you have design issues, especially when you feel that testing your code seems to be a bit difficult.
And indeed: You can/should improve the design of your software!
Let's start with your class (btw, I changed names to camel-casing):
public final class SomeTask {
public void sampleMethod(String filePath) {
Files.delete(new File(filePath).toPath);
}
}
I am going to ignore exceptions. Also, somewhere in your code you are using this class:
SomeTask task = new SomeTask();
String filePath = ...
task.sampleMethod(filePath);
The first thing to realize: In your class SomeTask you have a dependency to a delete-a-file functionality. Make this dependency visible!
But how do you do that? With an interface:
#FunctionalInterface
public interface FileDeletor {
void delete(String filePath);
}
You now can change your class by adding a field for such a deletor:
public final class SomeTask {
private final FileDeletor deletor;
public SomeTask(FileDeletor deletor) {
this.deletor = Objects.requireNonNull(deletor);
}
public void sampleMethod(String filePath) {
deletor.delete(filePath);
}
}
With this approach you delegate the technical doing of a file deletion to another class that now must implement the interface (shown below). This also makes your class more coherent because it now can concentrate on its own feature(s).
We now need a class that implements that interface:
public final class DefaultFileDeletor implements FileDeletor {
#Override
public void delete(String filePath) {
Files.delete(new File(filePath).toPath());
}
}
Note, that I am still ignoring exceptions here. Now we must also change the using side:
FileDeletor deletor = new DefaultFileDeletor();
SomeTask task = new SomeTask(deletor);
String filePath = ...
task.sampleMethod(filePath);
With this approach you can also build up an application via Spring autowiring or similar dependency injection frameworks.
Let us move on to the testing area. If you wish, you can also test your new class DefaultFileDeletor. But you know that it only uses a JDK functionality which itself is tested enough. No need to test this simple class.
But how can you now test your class SampleTask? First, you need an implementation of the interface just for the purposes of testing:
public class FileDeletorForTestPurposes implements FileDeletor {
private String filePath;
private boolean deleted;
#Override
public void delete(String filePath) {
this.filePath = filePath;
deleted = true;
}
public String getFilePath() {
return filePath;
}
public boolean isDeleted() {
return deleted;
}
}
Now you are able to test your code:
FileDeletorForTestPurposes deletor = new FileDeletorForTestPurposes();
SomeTask task = new SomeTask(deletor);
String filePath = ...
task.someMethod(filePath);
assertEquals(filePath, deletor.getFilePath());
assertEquals(true, deletor.isDeleted());
You are now also able to simply create a FileDeletor mock and use that by expressing expectations on it.
How to test delete files with Files.delete fuction below is the example
Lets say you have one function like below
public boolean deleteFilesWithinPath(Path path, int retryCount){
boolean status=false;
while (retryCount < 3) {
try {
Files.delete(path);
LOG.info("File deleted successfully from work Dir");
status=true;
break;
} catch (IOException e) {
try {
LOG.error(e.getMessage());
LOG.info("File was not deleted . Retrying ..");
status=false;
Thread.sleep(2000);
retryCount++;
} catch (InterruptedException e1) {
status=false;
LOG.error(e1.getMessage());
Thread.currentThread().interrupt();
}
}
}
return status;
}
Then you can test above function like below with Powermockit or Mockito
#Test
public void testdeleteFilesWithinPath() throws Exception{
File mockFileTemp = temporaryFolder.newFile("test.csv");
PowerMockito.mockStatic(Paths.class);
PowerMockito.mockStatic(Files.class);
int retrycount=0;
Path path = mockFileTemp.getAbsoluteFile().toPath();
boolean status = mftFileDownloadServiceImp.deleteFilesWithinPath(path,retrycount);
assertTrue(status);
}
#Test
public void testdeleteFilesWithinPathForIOException() throws Exception{
File mockFile = temporaryFolder.newFile("test.csv");
PowerMockito.mockStatic(Paths.class);
PowerMockito.mockStatic(Files.class);
Path path = mockFile.getAbsoluteFile().toPath();
Files.delete(path);
int retrycount=0;
try{
mftFileDownloadServiceImp.deleteFilesWithinPath(path,retrycount);
} catch (Exception e) {
assertThat(e).isInstanceOf(IOException.class);
}
}

How can I call a private method contained into a class that implements an interface, in a junit test?

edit: I apologize if the post has been considered too confusing, i'll edit it and leave only the parts regarding my problem...
I have written a class named "ArithmeticNode" which implements an interface containing the following methods:
public void turnOn() {
arithmeticServer.start();
}
public void turnOff(){
arithmeticServer.stop();
}
and contains also a private method:
private void negotiatePort(NodeManifest nodeManifest, ThriftServer arithmeticServer) {
while(true) {
int proposedPort = arithmeticServer.start();
int returnedPort = managementClient.registerNode(nodeManifest, proposedPort);
if(proposedPOrt != returnedPort) {
arithnemticServer.stop();
}
else
break;
}
}
What I'm trying to do is to write a test in which I create a number of these arithmetic nodes and make them register to a management node that I've already written and use as server. Then there will be a second part of my project where I'll make those nodes interact, but that's not part of the actual problem.
I have already written a working junit test:
#Test
public void testArithmeticServer() throws Exception {
List<NodeManifest> nodeManifests = new ArrayList<>();
nodeManifests.add(new NodeManifest("localhost", Arrays.asList(new String[]{"addition"})));
nodeManifests.add(new NodeManifest("localhost", Arrays.asList(new String[]{"subtraction","multiplication"})));
nodeManifests.add(new NodeManifest("localhost", Arrays.asList(new String[]{"addition","multiplication","division"})));
nodeManifests.add(new NodeManifest("localhost", Arrays.asList(new String[]{"addition","division"})));
List<ThriftServer> arithmeticServers = new ArrayList<>();
for (NodeManifest nodeManifest : nodeManifests) {
ThriftServer arithmeticServer = new ThriftServer(ArithmeticServiceHandler.class);
arithmeticServers.add(arithmeticServer);
negotiatePort(nodeManifest,arithmeticServer);
}
private void negotiatePort() {
while(true) {
int proposedPort = arithmeticServer.start();
int returnedPort = managementClient.registerNode(nodeManifest, proposedPort);
if(proposedPOrt != returnedPort) {
arithnemticServer.stop();
}
else
break;
}
}
I need to write a test where i don't have to put the negotiatePort method directly inside the test code, but I call for each node the private negotiatePort method I have inside my arithmeticNode class; I'm not sure if it's possible to do that and how. I hope I've been less confusing than the previous version of the post :-)
You can make the negotiatePort method package local. Then you would be able to call it within your test (which should reside in the same package). And nobody outside the package would be able to use it

Testing Java class

I am testing Java app with JUnit. The following is the source code of a specific method:
public class Surgery {
Vector<Patient> patients;
String name;
public Surgery(String name) {
patients = new Vector<Patient>();
this.name = name;
}
public Patient findPatient(String name) {
Iterator<Patient> patientIt = patients.iterator();
while(patientIt.hasNext()) {
Patient next = patientIt.next();
if (next.getName().equals(name))
return next;
}
return null;
}
This is JUnit test method:
public class SurgeryTest {
private Vector<Patient> vector;
Surgery surgery_N =new Surgery("Teddy");
ByteArrayOutputStream ans = new ByteArrayOutputStream();
final String separator = System.getProperty("line.separator");
#Test
public void testFindPatient() {
surgery_N.findPatient("Teddy");
}
}
I need to test each statement in the source code method. I stuck, don't know what else to do. Any solution?
Your Surgery class contains no way to add patients to it from the code sample you have given us, so your unit test should be finding nothing.
To test each statement in the source code method you should create multiple tests that cover each one of the possible paths in your code. That means, in your tests you will want to test for the scenario where you return a patient name if it exists, and one for where the patient doesn't exist (returning null).
Here's some example methods for you to work from:
public void testFindPatientWherePatientExists() {
Patient thePatient = surgery.findPatient("Teddy");
assertEquals("Teddy", thePatient.getName());
}
public void testFindPatientWherePatientDoesntExist() {
assertNull(surgery.findPatient("I dont exist"));
}
What is the expected result when you call findPatient(...)? You can compare the expected result with the actual result using assertEqual(...)
public class SurgeryTest {
Surgery surgery;
#Before
public void setUp() {
surgery = new Surgery("Teddy");
}
#Test
public void testFindPatient() {
Patient p = ...; // expected result
assertEquals(p, surgery.findPatient("Teddy"));
}
}
The method with #Before annotation will be called before each method with #Test annotation. Therefore, the new surgery object is tested every time.
First, note that the name you pass to the Surgery constructor does NOT get placed into the patients Vector. It is a field of Surgery. Suggest you rename the arg to "surgeryName" and then you'll need a new method, addPatient(String patientName);, and call addPatient("Teddy").
That said, in general, you should test for both the name present and name absent case. e.g.
(exact name of the assert methods might vary)
assertNotNull(surgery.findPatient("Teddy"));
assertNull(surgery.findPatient("A Name I did not add"));
(first line would be more precise if it were assertEquals() like wannik suggested.

How to test a ClassFileTransformer / javaagent?

I implemented a ClassFileTransformer for a javaagent using ASM. Because it has some bugs, I want to write a JUnit test case for it. How do I do this?
Using pseudo-code I thought along the lines:
// Have a test class as subject
public static class Subject {
public void doSomething(){...}
}
// Manually load and transform the subject
...?
// Normally execute some now transformed methods of the subject
new Subject().doSomething();
// Check the result of the call (i.e. whether the correct attached methods were called)
Assert.assertTrue(MyClassFileTransformer.wasCalled());
Now the question is: How do I manually load and transform the subject and make the JVM/Classloader use my manipulated version of it? Or do I completely miss something?
I got it. One needs to implement an own ClassLoader that does the same transformation with the test subject as the ClassFileTransformer (e.g. calls it). And of course the subject class may not already be loaded, so there may not be any direct usage of it. So I used Java reflection API to execute the methods of the subject class.
In a separate file:
public static class Subject {
public void doSomething(){...}
}
In the test:
private static class TransformingClassLoader extends ClassLoader {
private final String className;
public TransformingClassLoader(String className) {
super();
this.className = className;
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals(className)) {
byte[] byteBuffer = instrumentByteCode(fullyQualifiedSubjectClass);
return defineClass(className, byteBuffer, 0, byteBuffer.length);
}
return super.loadClass(name);
}
}
#Test
public void testSubject(){
ClassLoader classLoader = new TransformingClassLoader(fullyQualifiedSubjectClass);
Class<?> subjectClass = classLoader.loadClass(fullyQualifiedSubjectClass);
Constructor<?> constructor = subjectClass.getConstructor();
Object subject = constructor.newInstance();
Method doSomething = subjectClass.getMethod("doSomething");
doSomething.invoke(subject);
Assert.assertTrue(MyClassFileTransformer.wasCalled());
}

Categories

Resources