[JAVA] Ist das Testen von Einheiten mit der Konstruktorinjektion nicht einfacher? Sich unterhalten

Einführung

Dies ist "@ Autowired", das ich beim Schreiben von Code im Frühjahr unbedingt verwende. In letzter Zeit scheint eine Konstruktorinjektion anstelle einer Feldinjektion empfohlen zu werden.

Versuchen Sie es mit Google, um herauszufinden, warum die Injektion von Konstruktoren überhaupt empfohlen wird. Es gibt verschiedene Gründe, aber der, von dem ich am meisten überzeugt war, war "das? Ist das nicht ein Unit-Test?", Also schrieb ich darüber.

Es ist ärgerlich, sich lustig zu machen

Zu testende Klasse

Das Beispiel ist zu geeignet, aber wenn es eine Klasse gibt, die eine solche E-Mail sendet.

MailService.java


import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

@RestController
@RequestMapping(path="/mail")
public class MailService {

    @Autowired
    MailSender mailSender;

    @PostMapping
    public void send() {

        SimpleMailMessage msg = new SimpleMailMessage();
        msg.setFrom("[email protected]");
        msg.setTo("[email protected]");
        msg.setSubject("Hello World");
        msg.setText("Welcome to my world.");
       
        mailSender.send(msg);
    }
}

Testcode

Ich werde den Testcode schreiben.

MailServiceTest.java


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class MailServiceTest {

    @InjectMocks
    MailService mailService;

    @Mock
    MailSender mailSender;

    @Captor
    ArgumentCaptor<SimpleMailMessage> msgCaptor;

    @Test
    public void test() {
        //Ausführung der zu testenden Methode
        mailService.send();

        //Unter den getesteten Methoden ist mailSender#send wurde einmal ausgeführt
        //Erfassen Sie übrigens das Argument
        verify(mailSender, times(1)).send(msgCaptor.capture());

        //Überprüfen Sie den Inhalt des Arguments
        SimpleMailMessage msg = msgCaptor.getValue();
        assertThat(msg.getFrom(), is("[email protected]"));
        assertNotNull(msg.getTo());
        assertThat(msg.getTo().length, is(1));
        assertThat(msg.getTo()[0], is("[email protected]"));
        assertThat(msg.getSubject(), is("Hello World"));
        assertThat(msg.getText(), is("Welcome to my world."));
    }
}

Würde es in einer Klasse mit Feldinjektion so geschrieben werden? Ich hoffe, ich bin daran gewöhnt, aber ich vergesse jedes Mal, wie man Captor schreibt, und wenn ich nicht kommentiere (auch wenn es einen Kommentar gibt), kann ich ihn später nicht lesen, und es ist in erster Linie ärgerlich.

Versuchen Sie es mit einer Konstruktorinjektion

Zu testende Klasse (nur Korrekturen)

MailService.java


public class MailService {

    private final MailSender mailSender;

    @Autowired
    public MailService(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    //Folgendes wird weggelassen

Testcode

MailServiceTest.java


public class MailServiceTest {

    /**
     *Erstellen Sie Ihre eigene mailSender-Mock-Klasse
     */
    private class MailSenderMock implements MailSender {
        SimpleMailMessage simpleMessage;
        @Override
        public void send(SimpleMailMessage simpleMessage) throws MailException {
            this.simpleMessage = simpleMessage;
        }
        @Override
        public void send(SimpleMailMessage... simpleMessages) throws MailException {
        }
    }

    @Test
    public void test() {

        //Übergeben Sie die Scheinklasse, um eine Instanz zu erstellen
        MailSenderMock mailSenderMock = new MailSenderMock();
        MailService mailService = new MailService(mailSenderMock);

        //Ausführung der zu testenden Methode
        mailService.send();

        //Überprüfung
        SimpleMailMessage msg = mailSenderMock.simpleMessage;
        assertThat(msg.getFrom(), is("[email protected]"));
        assertNotNull(msg.getTo());
        assertThat(msg.getTo().length, is(1));
        assertThat(msg.getTo()[0], is("[email protected]"));
        assertThat(msg.getSubject(), is("Hello World"));
        assertThat(msg.getText(), is("Welcome to my world."));
    }
}

Im Beispiel wird die Scheinklasse als innere Klasse geschrieben, Sie können jedoch eine Klassendatei einzeln erstellen. Sie können es jedoch mit Mockito.mock schaffen. Es war das Ende der Geschichte, dass Mockito nervte, aber ... (Mockito.mock () ist möglicherweise gut für Klassen, in denen Sie nichts tun müssen.)

Es scheint, dass es keinen großen Unterschied gibt, da die Testzielklasse der Stichprobe zu einfach ist, aber ich dachte, es wäre einfach, sie nicht mit Mockito zu verspotten. Da es nicht mehr von SpringBoot abhängt, funktioniert JUnit aufgrund von Eigenschafteneinstellungen oder fehlendem DB nicht.

Solch eine Sache

Zum Beispiel können Sie ungefähr 3 "@ Autowired" haben und das Verhalten für nur einen Komponententest ändern. In diesem Fall setzen Sie es auf "@ SpringBootTest" und setzen Sie die Klasse, die das Verhalten nicht ändert, in der Testklasse auf "@ Autowired".

In diesem Fall hängt es vom Spring Boot ab. Ich möchte Testcode wie einen Integrationstest von Controller schreiben, aber es gibt eine Klasse, die im Weg steht! Manchmal finde ich diese Methode auch gut.

MailServiceTest.java


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class MailServiceTest {
    @Autowired
    HogeSerice hogeService;
    @Autowired
    FugaService fugaService;

    private class MailSenderMock {
        //Abkürzung
    }

    @Test
    public void test() {

        //Übergeben Sie die Scheinklasse, um eine Instanz zu erstellen
        MailSenderMock mailSenderMock = new MailSenderMock();
        MailService mailService = new MailService(mailSenderMock, hogeService, fugaService);
    //Abkürzung

Recommended Posts

Ist das Testen von Einheiten mit der Konstruktorinjektion nicht einfacher? Sich unterhalten
Testen mit com.google.testing.compile
[Java] So lassen Sie die Federkonstruktorinjektion mit Lombok weg