Using @Mock in Java

0

When using @Mock my @Test does not work although validating through a simple debug works completely, I do not understand how to use the Mocks and what I am testing is very simple:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
public class SepaRoutingFromXMLTest {

    @Mock
    SepaRoutingUtils sepa;

    @Test
    public void existValidOneFullXMLFileInFolder() throws Exception {
        assertThat("ARCHIVE_20141224.xml", containsString(".xml"));
        assertThat(sepa.readSepaXMLFile(), containsString("ARCHIVE_"));
    }

}

The first assertThat works without problem is very basic, however the second one that apparently is just as trivial returns me:

Expected: a string containing "SEPAROUTING_V3_FULL_" but: was null

As you can see I'm doing a mock of:

@Component
public class SepaRoutingUtils {

    public String readSepaXMLFile() {
        return "ARCHIVE_20141224.xml";
    }

}

That for me is basically the same, but I realize that I do not understand the functioning of @Mock and I can not do an @Autowired of that class because I think that should not be done in @Test.

I see that when doing the following modification works correctly:

@RunWith(SpringRunner.class)
public class SepaRoutingFromXMLTest {

    @Test
    public void existValidOneFullXMLFileInFolder() throws Exception {
        SepaRoutingUtils sepa = new SepaRoutingUtils(); 
        assertThat(sepa.readSepaXMLFile(), containsString(".xml"));
        assertThat(sepa.readSepaXMLFile(), containsString("ARCHIVE_"));
    }

}

However, doing this does not help me because in the class SepaRoutingUtils I must get a value with @Value:

@Value("${from.folder}")
private String FROM_FOLDER;

I know I can be wrong with several concepts.

Updating class SepaRoutingUtils

@Component
public class SepaRoutingUtils {

    @Value("${from.folder}")
    private String FROM_FOLDER;

    private File readSepaFolder() {

        File folder = new File(FROM_FOLDER);
        if(!folder.isDirectory()) {
            throw new FolderAccessDeniedException();
        }

        return folder;
    }

    public String readSepaXMLFile(SepaRoutingFileType fileType) {

        try {
            return Utils.prepareXMLFile(readSepaFolder(), fileType).getName();
        }
        catch (ParseException e) {
            e.printStackTrace();
            throw new NotValidFileException();      
        }

    }

}
    
asked by AndreFontaine 19.03.2018 в 12:46
source

2 answers

2

Complementing the correct answer in general terms of @ SJuan76.

For your particular case you want to make a mock of a private member that you can not do @Mock/@Spy because it is a final class (String)

A possible solution could be to use reflection to add a verifiable value to that String:

import org.springframework.util.ReflectionUtils;

@RunWith(MockitoJUnitRunner.class)
public class SepaRoutingUtilsTest {

    @InjectMocks
    private SepaRoutingUtils sepa;

    @Before
    public void setUp() throws NoSuchFieldException {
        Field field = SepaRoutingUtils.class.getDeclaredField("FROM_FOLDER");
        ReflectionUtils.makeAccessible(field);
        ReflectionUtils.setField(field, sepa, "ARCHIVE_20141224.xml");
    }

    @Test
    public void existValidOneFullXMLFileInFolder() throws Exception {
        assertThat("ARCHIVE_20141224.xml", containsString(".xml"));
        assertThat(sepa.readSepaXMLFile(), containsString("ARCHIVE_"));
    }

}
    
answered by 19.03.2018 / 14:16
source
1

You make mocks to replace components on which the code you test depends. This way you can test a component without depending on whether the replaced components work correctly or not.

Your component makes such that 1 :

public MiComponente {
   @Autowired MiComponentePersistencia persistencia;

   public int getSuma(String param) {
      int[] datos = persistencia.getNumeros(param);
      int resultado = 0;
      for (int dato : datos) {
         resultado += dato;
      }
      return resultado;
   }
}

How do you test getSuma() ? The value you get depends on what persistencia.getNumeros() returns, so if you do not control that you can not do the test (or at least, you can not validate the result).

So

@Mock
MiComponentePersistencia persistencia;

@InjectMocks
MiComponente compAProbar;

@Test
public void testSuma() {
   when (persistencia.getNumeros("hola")).thenReturn(new int[]{1, 2});
   assertEquals("Valor de la suma", 3, compAProbar.getSuma("hola"));
}

And yes, you could just do your implementation "by hand" of MiComponentePersistencia to do the same. The mock frameworks simply make the task much easier.

1 I really have more experience with Java EE and Mockito than with Spring, so you'll excuse me if something from Spring is not totally right.

    
answered by 19.03.2018 в 13:06