[JAVA] Testcode mit Mock mit JUnit (EasyMock Center)

Über das Testen mit Mock in JUnit. Dies ist der zweite Artikel zur Verbreitung von Testcode am Arbeitsplatz. Es ist keine sehr junge Geschichte, da sie sich auf EasyMock konzentriert.

Ausführungsumgebung

Was ist ein Schein

Ein Mock-Objekt ist eine Art unterer Modul-Stub, der Softwaretests ersetzt, insbesondere bei testgetriebener Entwicklung und verhaltensgetriebener Entwicklung. Zu prüfendes Modul im Vergleich zum Stummel Wird verwendet, um zu überprüfen, ob die Submodule korrekt verwendet werden.

Scheinobjekt Quelle: Freie Enzyklopädie "Wikipedia"

Angenommen, Sie haben eine Klasse namens HelloJunit wie unten gezeigt erstellt, um sie zu verwenden. Wenn Sie versuchen, diese Klasse zu testen, wenn die GreetDao-Klasse nicht erstellt wird (und die von Dao referenzierte Datenbank nicht vorbereitet ist), tritt beim normalen Testen ein Fehler auf. Ich denke, es wird enden.

HelloJunit


public class HelloJunit {

	@Binding
	GreetDao greetDao;

	public String sayGreeting() {
		return greetDao.getGreet();
	}

Ursprünglich möchte ich nur die HelloJunit-Klasse testen, damit ich sie auch dann testen kann, wenn der Code der Abhängigkeit (GreetDao) nicht erstellt wurde. Bereiten wir also eine Haribote-Klasse vor, damit sie vorerst funktioniert. Das ist die Rolle des Mocks.

Wie man einen Spott macht

Es gibt die folgenden Methoden.

Zu den Mock-Bibliotheken gehören "Mockito", "JMockit" und "EasyMock", "MockInterceptor".

Ich habe den Eindruck, dass "Mockito" heutzutage oft verwendet wird.

In Seasar2 sind "EasyMock" und "MockInterceptor" standardmäßig enthalten. Ich denke, es ist schwierig, eine neue Bibliothek in einer Umgebung zu installieren, in der Seasar2 noch verwendet wird. Daher möchte ich dieses Mal mit EasyMock fortfahren.

Testen Sie das Codebeispiel mit EasyMock

Code vorerst

Der Produktcode wurde gegenüber dem oben eingeführten Inhalt geringfügig geändert.

Produktcode


public class HelloJunit {

	GreetDao greetDao;
	
	public HelloJunit(GreetDao greetDao) {
		this.greetDao = greetDao;
	}

	public String sayGreeting() {
		return greetDao.getGreet();
	}
}

Hier ist der Testcode.

Testcode


import static org.easymock.EasyMock.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.seasar.framework.unit.annotation.EasyMock;
import org.seasar.sastruts.example.dao.GreetDao;

public class HelloJunitTest {

	HelloJunit helloJunit;

	@EasyMock
	GreetDao greetDao;

	@Before
	public void setUp() {
		greetDao = createMock(GreetDao.class);
		helloJunit = new HelloJunit(greetDao);
	}

	@Test
öffentliche Leere sagen einen Gruß() throws Exception {
		//installieren
		expect(greetDao.getGreet()).andReturn("Hello");
		replay(greetDao);

		//Übung
		String actual = helloJunit.sayGreeting();

		//überprüfen
		String expected = "Hello";
		assertThat(actual, is(expected));
		verify(greetDao);

		//abreißen (Nachbearbeitung)
		//wenn Sie Probleme haben ···
	}
}

Ich denke, Sie können es irgendwie verstehen, aber ich werde es erklären.

EasyMock-Anmerkung

Ich habe GreetDao als Mitgliedsvariable, aber es hat eine "EasyMock-Annotation". Durch Anhängen können Sie EasyMock verwenden.

createMock Die setUp-Methode verwendet die Methode createMock, um ein greetDao zu erstellen. Der Mock wird festgelegt, indem das hier erstellte greetDao beim Erstellen der Instanz von helloJunit übergeben wird, bei der es sich um die Testzielmethode handelt.

Setup in der Testmethode

Die "Expect" -Methode wird im Kommentar-Setup verwendet. Dies ist der wichtigste Teil, der das Verhalten des Mocks bestimmt.

Wenn greetDao.getGreet () so aufgerufen wird, wird ~ zurückgegeben. Geben Sie an, wie die Methode mit expected () aufgerufen werden soll. Verwenden Sie dann andReturn (), um den Rückgabewert festzulegen. In diesem Fall wird "Hallo" zurückgegeben, wenn greetDao.getGreet () ohne Argument aufgerufen wird.

Die Methode "Wiedergabe" ist ein Bild, das sich an das Verhalten des unmittelbar vorher festgelegten Mock-Sets erinnert. Stellen Sie sicher, dass Sie nach der Ausführung von expected () erneut spielen.

exercise Hier wird die zu testende Methode ausgeführt und in einer Variablen gespeichert. Es wird gesagt, dass es leicht zu verstehen ist, ob die gespeicherten Variablen unabhängig vom Typ zu "tatsächlich" vereinheitlicht werden.

verify Hier vergleichen wir den Rückgabewert und den erwarteten Wert von helloJunit.sayGreeting ();. Außerdem überprüft verify (greetDao);, ob das im Setup angegebene Verhalten des Mocks wie erwartet aufgerufen wurde. Wenn helloJunit.sayGreeting (); noch nie aufgerufen wurde, wird ein Fehler zurückgegeben.

tear down Dies ist die Nachbearbeitung nach dem Test. Wenn beispielsweise Testdaten in die Datenbank eingegeben wurden, werden diese Daten gelöscht.

Verwendung von EasyMock

Überprüfen Sie das Argument

Überprüfen Sie diesmal, ob die findDreet-Methode von greetDao wie erwartet aufgerufen wird.

Zu testender Code


public String sayGreeting() {
	return greetDao.findGreet(1);
}

Schreiben Sie in expected () die erwartete Methodenaufrufmethode so wie sie ist. In diesem Fall wird angenommen, dass 1 im Argument von "findGreet" enthalten ist. Beschreiben Sie also einfach "findGreet (1)".

Testcode


@Test
öffentlicher Test für nichtige Argumente() throws Exception {
	//installieren
	expect(greetDao.findGreet(1)).andReturn("Hello");
	replay(greetDao);

	//Übung
	String actual = helloJunit.sayGreeting();

	//überprüfen
	verify(greetDao);
}

Übrigens, wenn es von findGreet (2); aufgerufen wird, wird der folgende Fehler ausgegeben.

Referenz im Fehlerfall


java.lang.AssertionError: 
  Unexpected method call findGreet(2):
    findGreet(1): expected: 1, actual: 0
	at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32)
	at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)
	at com.sun.proxy.$Proxy4.findGreet(Unknown Source)
	at org.seasar.sastruts.example.service.HelloJunit.sayGreeting(HelloJunit.java:17)
	at org.seasar.sastruts.example.service.HelloJunitTest.Argument Test(HelloJunitTest.java:52)
--Danach weggelassen--

Stellen Sie den Rückgabewert ein und testen Sie die nachfolgende Verarbeitung

Ich habe versucht, einen Zweig mit dem Rückgabewert von findGreet einzufügen. In diesem Test möchte ich das Muster testen, in dem Nudeln zurückgegeben werden.

Produktionscode


public String sayGreeting() {
	String greet = greetDao.findGreet(1);
	if (greet.contentEquals("Hello")) {
		return "Pasta";
	} else {
		return "Ramen";
	}
}

Um den Rückgabewert festzulegen, geben Sie den Rückgabewert in "andReturn" an. In diesem Fall wird "Hallo" zurückgegeben.

Testcode


@Test
öffentlicher Test für nichtige Argumente() throws Exception {
	//installieren
	expect(greetDao.findGreet(1)).andReturn("Hello");
	replay(greetDao);

	//Übung
	String actual = helloJunit.sayGreeting();

	//überprüfen
	String expected = "Pasta";
	assertThat(actual, is(expected));
	verify(greetDao);
}

Testen Sie Methoden vom Typ Void

So testen Sie eine Methode vom Typ void.

Produktionscode (GreetDao)


public interface GreetDao {
	public void insertGreet(String greet);
}

Produktionscode (HelloJunit)


public String addGreet() {
	greetDao.insertGreet("Good Night");
	return "OK";
}

Wenn Sie den Void-Typ testen möchten, führen Sie die Void-Methode in Ihrem Testcode aus. Rufen Sie dann expectedLastCall () auf. Auf diese Weise können Sie sich die letzte Methodenausführung merken und überprüfen.

Übrigens, wenn dieselbe void-Methode zweimal ausgeführt wird, wird durch Hinzufügen von times () wie "awaitLastCall (). Time (2);" überprüft, ob sie so oft ausgeführt wurde.

Testcode


@Test
Test Public Void Void Methode() throws Exception {
	//installieren
	greetDao.insertGreet("Good Night");
	expectLastCall();
	replay(greetDao);

	//Übung
	String actual = helloJunit.sayGreeting();

	//überprüfen
	verify(greetDao);
}

Easy Mock Notizen

EasyMock kann nur Schnittstellenklassen verspotten. Wenn Sie eine konkrete Klasse verspotten möchten, versuchen Sie die folgende Vererbungsmethode.

Erben und überprüfen

Wenn die in der zu testenden Methode verwendete Klasse keine Schnittstelle ist oder das Testen unpraktisch ist, können Sie sie zum Testen erben und Ihre eigene Scheinklasse vorbereiten.

Wenn beispielsweise die von der Methode zurückgegebenen Beans die Methode equals nicht überschreiben und es schwierig ist, jedes Feld zu überprüfen, erben Sie equals und testen Sie wie folgt.

Zu testender Produktionscode


public TransferResultDto transfer(String payerAccountId,
										String payeeAccountId,
										String payerName,
										long transferAmount) {

		Balance payerBalance = balanceDao.findByAccountId(payerAccountId);
		if (payerBalance == null)
			throw new BusinessLogicException("Ich kann das Gleichgewicht nicht bekommen");

		if (transferAmount > payerBalance.amount)
			throw new BusinessLogicException("Nicht genug Gleichgewicht");

		Balance payeeBalance = balanceDao.findByAccountId(payeeAccountId);
		if (payeeBalance == null)
			throw new BusinessLogicException("Das Überweisungskonto existiert nicht");

		LocalDateTime transferDate = LocalDateTime.now();

		Transfer peyerTransaction = new Transfer();
		peyerTransaction.accountId = payerAccountId;
		peyerTransaction.name = payerBalance.name;
		peyerTransaction.transferAmount = -transferAmount;
		peyerTransaction.transferDate = transferDate;

		Transfer payeeTransaction = new Transfer();
		payeeTransaction.accountId = payeeAccountId;
		payeeTransaction.name = payeeBalance.name;
		payeeTransaction.transferAmount = transferAmount;
		payeeTransaction.transferDate = transferDate;

		transferDao.insertTransfer(peyerTransaction);
		transferDao.insertTransfer(payeeTransaction);
		balanceDao.updateAmount(payerAccountId, -transferAmount);
		balanceDao.updateAmount(payeeAccountId, transferAmount);

		Balance updatedPayerBalance = balanceDao.findByAccountId(payerAccountId);

		return new TransferResultDto(payerAccountId, payeeAccountId,
									 payerBalance.name, payeeBalance.name,
									 transferAmount,
									 updatedPayerBalance.amount);
	}
}

Bring Bean zurück


public class TransferResultDto {

	private final String payerAccountId;
	private final String payeeAccountId;
	private final String payerName;
	private final String payeeName;
	private final long transferAmount;
	private final long amount;

	public TransferResultDto(String payerAccountId,
							 String payeeAccountId,
							 String payerName,
							 String payeeName,
							 long transferAmount,
							 long amount) {

		this.payerAccountId = payerAccountId;
		this.payeeAccountId = payeeAccountId;
		this.payerName = payerName;
		this.payeeName = payeeName;
		this.transferAmount = transferAmount;
		this.amount = amount;
	}

	public String getPayerAccountId() {
		return payerAccountId;
	}

	public String getPayeeAccountId() {
		return payeeAccountId;
	}

	public String getPayerName() {
		return payerName;
	}

	public String getPayeeName() {
		return payeeName;
	}

	public long getTransferAmount() {
		return transferAmount;
	}

	public long getAmount() {
		return amount;
	}

}

Um dies zu testen, erstellen Sie eine "TransferResultDtoMock" -Klasse, die von "TransferResultDto" in der Testklasse erbt. Bereiten Sie in dieser Klasse "TransferResultDtoMock" eine Methode equals vor, die alle Felder vergleicht. Beim Testen können Sie mit "assertThat (actual, is (erwartet))" vergleichen.

python


public class TransferServiceTest {
	@Test
public void try vererbung verspotten() {
		// setup
		TransferResultDtoMock expected = 
						new TransferResultDtoMock("1", "2",
												ACCOUNT1_BEFORE_BALANCE.name, ACCOUNT2_BALANCE.name,
												2000, ACCOUNT1_AFTER_BALANCE.amount);

		TransferResultDto transferResultDto = transferService.transfer("1", "2", "Taro Tanaka", 1000);
		TransferResultDtoMock actual = new TransferResultDtoMock(transferResultDto);
		assertThat(actual, is(expected));
	}


	@EqualsAndHashCode(callSuper = true)
	private class TransferResultDtoMock extends TransferResultDto {
		public TransferResultDtoMock(String payerAccountId,
									 String payeeAccountId,
									 String payerName,
									 String payeeName,
									 long transferAmount,
									 long amount) {

			super(payerAccountId, payeeAccountId, payerName,
					payeeName, transferAmount, amount);

		}

		public TransferResultDtoMock(TransferResultDto transferResultDto) {
			super(transferResultDto.getPayerAccountId(),
				  transferResultDto.getPayeeAccountId(),
				  transferResultDto.getPayerName(),
				  transferResultDto.getPayeeName(),
				  transferResultDto.getTransferAmount(),
				  transferResultDto.getAmount());
		}
				

	}
}

Dinge, die Sie beim Schreiben von Testcode beachten sollten

Machen Sie den Teil, der sich auf die Geschäftslogik bezieht, zu einer unabhängigen Implementierung

Zunächst haben Sie die Logik in HelloJunit von Annotation auf Konstruktortyp in DI GreetDao geändert. Der Grund dafür ist, dass HelloJunit, wenn es durch Anmerkungen ausgedrückt wird, je nach Framework (Seasar2) zu einer ** abhängigen </ font> ** Form wird.

Produktcode


public class HelloJunit {

	GreetDao greetDao;
	
	public HelloJunit(GreetDao greetDao) {
		this.greetDao = greetDao;
	}

	public String sayGreeting() {
		return greetDao.getGreet();
	}
}

Wenn Sie sich beispielsweise für einen zukünftigen Wechsel zu Spring entscheiden, verwenden Sie @ Autowired to DI mit Anmerkungen. Daher ist es einfach, durch DI im Konstruktor auf das Framework zu wechseln.

Unter dem Gesichtspunkt des Testcodes muss beim Deklarieren der Klasse "@ RunWith (Seasar2.class)" angegeben werden, wenn dies durch Annotation realisiert wird. Wenn es sich jedoch um DI im Konstruktor handelt, ist new Wenn Sie dies tun, können Sie leicht testen.

Referenzartikel

Praktisch saubere Architektur

Schreiben Sie Code, mit dem Sie einfach Tests schreiben können

Einfach zu schreibender Code ist wichtig zum Testen.

Der folgende Code erstellt beispielsweise eine bedingte Verzweigung gemäß dem Ergebnis der statischen Methode "TimeJunit.getTime ()". Es ist jedoch schwierig, die statische Methode durch eine Scheinmethode zu ersetzen.

Mit statischer Methode


public class ExampleJunit {
	public String sayGreeting() {
		int term = TimeJunit.getTime();
		switch(term) {
		case 1:
			return "Pasta";
		case 2:
			return "Ramen";
		default:
			return "Reis";
		}
	}
}

Der Rest des Codes ist schwer zu testen, selbst wenn er vererbt wird und Methoden der Oberklasse verwendet. Zum Beispiel diese Art von Logik, die häufig in älteren Systemen verwendet wird.

Super Klasse


public abstract class AbstractJunit {
	public String sayGreeting() {
		return this.getMessage();
	}
	abstract protected String getMessage();
}

Vererbungsklasse


public class ExampleJunit extends AbstractJunit {
	protected String getMessage() {
		int term = 1;
		switch(term) {
		case 1:
			return "Pasta";
		case 2:
			return "Ramen";
		default:
			return "Reis";
		}
	}
}

In diesem Beispiel kann es getestet werden, aber in dem Fall, in dem Vererbung tatsächlich im Geschäftsleben verwendet wird, ist die Superklasse eine Gottklasse (eine bequeme Klasse, um Logik in irgendetwas zu setzen) und eine Spaghettiquelle. Es ist umständlich, weil ich im Test nachdenken muss.

Überlegen Sie, ob Sie die Vererbung wirklich verwenden und implementieren sollten.

Referenzartikel

Code, der einfach zu schreiben ist, ist guter Code

andere Referenzen

http://s2container.seasar.org/2.4/ja/easyMock.html

Recommended Posts

Testcode mit Mock mit JUnit (EasyMock Center)
Machen Sie einen Unit-Test mit Junit.
[JUnit 5-kompatibel] Schreiben Sie einen Test mit JUnit 5 mit Spring Boot 2.2, 2.3
Testen Sie die Web-API mit junit
Ich habe eine InvalidUseOfMatchersException erhalten, wenn ich eine in JUnits Mock verwende
Testen Sie den Spring Framework Controller mit Junit
Steuern Sie die Testreihenfolge in Junit4 mit einem Aufzählungstyp
Versuchen Sie es mit Spring Boot mit VS-Code
So testen Sie den privaten Bereich mit JUnit
Der JUnit 5-Gradle-Test führt zu einem Fehler mit der Lombok-Annotation
Einführung eines automatisierten Java-Tests mit JUnit 5 + Gradle
[Java] So testen Sie, ob es in JUnit null ist
[CircleCI 2.0] [Java] [Maven] [JUnit] Aggregieren Sie die JUnit-Testergebnisse mit CircleCI 2.0
Testen Sie den Controller mit Mock MVC im Spring Boot
Ausführen einer Methode und Verspotten mit JUnit
Umgebungskonstruktionsverfahren für die Verwendung von PowerMock mit JUnit
Einführung automatisierter Java-Tests mit JUnit 5 + Apache Maven
So testen Sie Interrupts während Thread.sleep mit JUnit
Einfacher JUnit-Test der Elasticsearch 2018-Version mit Embedded-Elasticsearch
So schreiben Sie Testcode mit Basic-Zertifizierung
Machen Sie System.out Mock mit dem Spock Test Framework
Tipps zum Testen mit Mock für Klassen mit @value
Mischen Sie Testfälle mit JUnit 5 und Standardmethoden
Erste Schritte mit Java-Programmen mit Visual Studio Code
So führen Sie mit RxAndroid einen Komponententest mit JVM an einer Quelle durch
Implementieren Sie Test Double in JUnit, ohne externe Bibliotheken zu verwenden
Web-API-Komponententest und Integrationstest mit SpringBoot + Junit5, 4 Muster
Ich habe jetzt einen Test mit Spring Boot + JUnit 5 geschrieben