1
Greetings,
I have a class that does actions in an email. I created some tests for this class and would like to know if this is a valid form of testing or if there is any better way to do it.
I test the reading of emails and then test move messages from one folder to another, but the messages that will be moved depend on the reading. Therefore I need to call the read method inside the drive method as well so that I can move at least one message. Ideally Mock the Message Array?
I am perfecting my studies in tests yet, so feel free to criticism and suggestions
Below is the test class:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@ActiveProfiles("teste")
public class EmailTest {
ReadEmail readEmail = new ReadEmail();
MoveMessages moveMessages = new MoveMessages();
private static final Logger LOGGER = LoggerFactory.getLogger(EmailTest.class.getSimpleName());
@Test
public void readEmail() {
Message[] messages = new Message[0];
ReflectionTestUtils.setField(readEmail, "usuario", "usuario");
ReflectionTestUtils.setField(readEmail, "senha", "senha");
ReflectionTestUtils.setField(readEmail, "host", "host");
try {
messages = readEmail.read();
} catch (EmailException e) {
Assert.assertTrue(e.getMessage().contains("!! ERRO AO CAPTURAR AS MENSAGENS"));
}
assert Objects.nonNull(messages);
Assert.assertTrue(messages.length > 0);
Assert.assertTrue(Arrays.stream(messages).anyMatch(message -> {
try {
return InternetAddress.toString(message.getFrom()).contains("@domain.com.br");
} catch (MessagingException e) {
LOGGER.error("Erro ao buscar remetente");
}
return false;
}));
}
@Test
public void moveEmail() {
Message[] messages = new Message[0];
ReflectionTestUtils.setField(readEmail, "usuario", "usuario");
ReflectionTestUtils.setField(readEmail, "senha", "senha");
ReflectionTestUtils.setField(readEmail, "host", "host");
try {
messages = readEmail.read();
} catch (EmailException e) {
LOGGER.error("Erro ao capturar mensagens para serem movidas: {}", e.getMessage());
}
assert Objects.nonNull(messages);
assert messages.length > 0;
Message[] messagesParam = new Message[1];
messagesParam[0] = messages[0];
try {
moveMessages.move("Inbox", "teste", messagesParam);
} catch (EmailException e) {
Assert.assertTrue(e.getMessage().contains("!! ERRO AO MOVER AS MENSAGENS"));
}
// ASSERTS ...
}
}
Thank you.
You have the following test contexts: 1) Test read 2) Test move 3) Test both integrally. To test the move, you don’t need to read the messages, just provide a mock of
messagesParam
and perform the necessary checks on the mocks. To read the same thing. Now for the integrated test, you should read and move in the same test, not in separate tests– nullptr
But if I mock the data on
read
how do I know if the search really works? I’m bringing my email messages. And onmove
the same thing. All right, I can even mock a real message from my email in that case, but if one day I delete that message for example, my test crashes because it will no longer locate the message in the email to move it.– Gustavo
Here’s the thing, it only makes sense for you to provide a mock if you’re performing unit tests to check just the
read
and only themove
. For the integrated test you should provide a message in the box to beread
, then carry out themove
in the same test, without mock any– nullptr
So it doesn’t make any sense for me to test the method
read
if you think about it. Because it just goes to the email box and brings all the messages from a particular sender. My test is based on seeing if it actually brings these messages. If I’m going to mock the messages, there’s nothing to test for this method. Correct?– Gustavo
What’s in the classes
ReadEmail
andMoveMessages
?– Victor Stafusa
The classes are large, but the
ReadEmail
searches for unread emails from an email filtering by a specific sender. The classMoveMessages
moves emails read and filtered byReadEmail
to a different folder. You need the codes ?– Gustavo
Then spring has notes for you to create mocks and simulate the behavior This is the documentation of the Spring Mocks. <- There are examples of use. D
– Yuri Zamboni
The idea of unitary testing is to test one thing only: if everything else works, does that particular stretch also work? To simulate "everything else working", mocks are used. If testing only the
read
, just check if the return has the correct messages. If you are testing only themove
, theread
is part of "all the rest", so he must be mockery (then you can create several scenarios: a list with multiple messages, an empty list, etc.). If you want to test two features (read + move) working together, it is no longer a unit test: https://stackoverflow.com/a/2741845– hkotsubo
@Yurizamboni @hkotsubo Perfect, I understood that the ideal is to mock the messages. But imagine that I mock a message to the
move
move it. If this message does not exist in the email, it will return error, right?? My methodmove
depends on the valid messages that my read brings. So I couldn’t leave this test in the code. I don’t know if you can understand the scenario I’m imagining.– Gustavo
Well, the unit test should not read the emails of an "official"/real/production box (just as a unit test should not access the bank, nor call services in real Urls on other machines, etc.), it should run in isolation, without external dependencies. You should have a box mockery (that behaves as if it were real), then you can manipulate it at will, without needing there to be emails in the real Inbox. So you do not depend on external factors and can still create various scenarios (empty Inbox, with multiple emails, etc). If you want to test with real emails, it’s no longer Unit test...
– hkotsubo
@hkotsubo I understand. Mt thank you !
– Gustavo