How to apply unit test when the main class is an interface?

Asked

Viewed 603 times

-4

I have this method in my Beginning class

@Override
public void question() {
    String question = String.format(TEXT_OF_A_QUESTION, this.namePlate);
    int answer = JOptionPane.showConfirmDialog(null, question, "Question", JOptionPane.YES_NO_OPTION);

    if (Integer.valueOf(answer).equals(JOptionPane.YES_OPTION)) {
        this.positive.positiveAnswer();
    } else {
        this.negative.negativeAnswer(this);
    }
}

How do I create a unit test to test this method? I’m having problems because my model is an interface as you can see below;

package com.test.wladimir.gamergourmet.model;

public interface Plate {

    String namePlate();

    void question();

    void questionLevel(String positiveAnswer, String negativeAnswer);

    void positiveAnswer();

    void negativeAnswer(Plate plate);
}

This is my APPLYING

That was my attempt;

@RunWith(MockitoJUnitRunner.Silent.class)
public class BeginningTest {

    private static final String TEXT_OF_A_QUESTION = "O prato que você pensou é %s?";
    private static String namePlate = "torta";

    private Plate positive;
    private Plate negative;

    @Mock
    private Beginning beginningController;

    @Before
    public void setUp() {
        beginningController = new Beginning(namePlate);
    }

    @Test
    public void testQuestion() {

        String question = String.format(TEXT_OF_A_QUESTION, this.namePlate);
        assertThat(question, notNullValue());

    }

But I don’t know if I’m right!

  • 1

    Mocking with an interface is easier than with classes. Use Mockito methods to manage the creation of the interface instance, avoid creating at hand (except if your goal is to run the test without the Mockito)

1 answer

1

The first thing to understand is to know what you want to test.

In your code, you can test the following items:

  • Return of String.format in the TEXT_OF_A_QUESTION
  • Condition within the if

To first difficulty to test your code is this JOptionPane.showConfirmDialog. You need to somehow put an interface in place and change its implementation in the test.

For example:

class Beginning {

    private OptionPane optionPane = new DefaultOptionPane();

    private String namePlate;
    private Plate positive;
    private Plate negative;

    @Override
    public void question() {
        String question = String.format(TEXT_OF_A_QUESTION, this.namePlate);
        int answer = optionPane.showConfirmDialog(null, question, "Question", JOptionPane.YES_NO_OPTION);

        if (Integer.valueOf(answer).equals(JOptionPane.YES_OPTION)) {
            this.positive.positiveAnswer();
        } else {
            this.negative.negativeAnswer(this);
        }
    }

    public void setOptionPane(OptionPane o) { this.optionPane = o; }

}

And the implementation of the 2 classes you will need: one with the implementation for the application and the other for the unit test:

public class DefaultOptionPane implements OptionPane {

      public int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) {
         return JOptionPane.showConfirmDialog(parentComponent,message,title,optionType,messageType);
      }
}

public class YesMockOptionPane implements OptionPane {

        @Override
 public int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) {
   return JOptionPane.YES_OPTION;
 }
}

By default, your code will always use the DefaultOptionPane, but in your test you can overwrite it via the method the setOptionPane.

Then, basically you will need to abuse the methods verify of the mockito to understand whether the positive or negative is called, depending on the return of the optionPane. But their original code instantiates them internally, this is bad to mock them, because it will also need to expose them. You can do this by creating methods set for them too, although in practice the ideal was that they had been injected via constructor, hence you can use the same entry point to pass the mocked classes.

I’ll set an example using set really. It would be something like your test:

@Test
public void test() throws Exception {

  OptionPane optionPane = mock(OptionPane.class);
  when(optionPane.showConfirmDialog(any(),any(),any(),any()).thenReturn(1); // 1 = Yes, eu acho...

  Pane negative = mock(Pane.class);
  Pane positive = mock(Pane.class);

  Beginning b = new Beginning ("lagosta");
  b.setOptionPane(optionPane);
  b.setNegative(negative);
  b.setPositive(positive);

  verify(positive, times(1)).positiveAnswer();
  verify(positive, times(0)).negativeAnswer(any());
}

I believe you got the idea. The test of String.format can be done via mock, waiting for the desired result as method input point showConfirmDialog, something like that:

when(optionPane.showConfirmDialog(any(),eq("O prato que você pensou é lagosta"),any(),any()).thenReturn(1);
  • It was well explained, but in class DefaultOptionPane no interface exists OptionPane, I am using netbeans and asked him to research the dependency, and did not find it, and researched the dependency manually on the internet, and also did not find, and also did not import the class YesMockOptionPane, because you say it doesn’t exist. unfortunately it was not possible to apply to my project because of this, my repository is in the post, if you can take a look and show how to import these classes, it will be very important to me!

  • 1

    Hello! I believe your class can implement any interface. You can create your own interface OptionPane and use it the way I put it. The YesMockOptionPane is a class that does not exist, you will also need to create it (with the code I put). The example I gave above was to understand the idea.

  • thanks for trying to help me

Browser other questions tagged

You are not signed in. Login or sign up in order to post.