0

New in JUnit here. I am using JUnit 4 with Mockito. How do I write junit for "if" condition?

Note: I am trying to cover inside the if statement when question is not null. Hopefully my question makes sense.

public class MyClass{
    private HttpServletRequest request;
    private A a;    
    private B b;

public void go(String something, String s){
MyQuestion question = Exam.getSubject().getMarks(a.getAId, b.getBId(), something);
  
   if(question !=null){
       request.setAttribute(s, question);
    }
 }

}

// getMarks I do have catching an exception Here is the snippet:

    public class MarksClass{
    Public MyQuestion getMarks(long idA, long IdB, String s){        
    try{
    //some code
    }catch(Exception e){
        throw new SomeException("exception" + e);
       }
  }
}
knittl
  • 246,190
  • 53
  • 318
  • 364
SeanAle
  • 1
  • 1

2 Answers2

0

Assuming, "getSubject" returns a field with name "subject".

final HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
ReflectionTestUtils.setField(myClass, "request", mockedRequest);
final MarksClass mockedMarksClass = Mockito.mock(MarksClass.class);
final MyQuestion mockedResult = Mockito.mock(MyQuestion.class);
Mockito.when(mockedMarksClass.getMarks(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString()).thenReturn(mockedResult);
ReflectionTestUtils.setField(myClass, "subject", mockedMarksClass);
//... rest of the test
Ankit Sharma
  • 1,626
  • 1
  • 14
  • 21
0

Design your class in such a way that testing becomes easy. Or change the design so that it can be tested more easily.

Having global singletons makes testing difficult, if not impossible. The general way forward is to have a class injected with all its external dependencies (DI, dependency injection) or pass the dependencies as arguments to the method.

public class MyClass {
    private HttpServletRequest request;
    private A a;    
    private B b;
    private final Supplier<Subject> subjectFactory;

    public MyClass(final Supplier<Subject> subjectFactory) {
      this.subjectFactory = subjectFactory;
    }

    public void go(String something, String s){
      final MyQuestion question = subjectFactory.get().getMarks(a.getAId, b.getBId(), something);
  
      if(question !=null){
        request.setAttribute(s, question);
      }
    }
}

Then in your real code, initialize the class with a method reference to the method on your singleton:

final MyClass myClass = new MyClass(Exam::getSubject);

And in your test inject a test double:

new MyClass(() -> new Subject() {
    @Override
    public MyQuestion getMarks(…) {
      return null;
    }
);

Of course, nothing is prevent you from changing the Supplier<Subject> to a Supplier<MyQuestion>, Function<String, MyQuestion>, or a custom interface; and then replacing this with a test double.

@FunctionalInterface
public interface Grader {
  MyQuestion getMarks(String idA, String idB, String something);
}
public class MyClass {
    private HttpServletRequest request;
    private A a;    
    private B b;
    private final Grader grader;

    public MyClass(final Grader grader) {
      this.grader = grader;
    }

    public void go(String something, String s){
      final MyQuestion question = grader.getMarks(a.getAId, b.getBId(), something);
  
      if(question !=null){
        request.setAttribute(s, question);
      }
    }
}

And then again in your production code vs your test code:

final MyClass production = new MyClass(Exam.getSubject()::getMarks);
final MyClass underTest  = new MyClass((a, b, something) -> null);

Providing different implementations of this interface can make your code a bit more expressive:

public class ExamSubjectGrader implements Grader {
  @Override
  public MyQuestion getMarks(String idA, String idB, String something) {
    return Exam.getSubject().getMarks(idA, idB, something);
  }
}
public class NullGrader implements Grader {
  @Override
  public MyQuestion getMarks(String idA, String idB, String something) {
    return null;
  }
}
MyClass production = new MyClass(new ExamSubjectGrader());
MyClass underTest  = new MyClass(new NullGrader());

(both of those are actually singletons, but they could have their own dependencies or state).

And as you can see: you don't even need a heavy mocking library such as Mockito. Good ol' Java can do that just fine.

Find more details in the question Why is my class not using my mock in unit test?

knittl
  • 246,190
  • 53
  • 318
  • 364