Java >> Java Tutorial >  >> Tag >> new

Saubere Tests schreiben – neu als schädlich angesehen

Das Erstellen neuer Objekte ist ein wesentlicher Bestandteil des automatisierten Testens, und der naheliegendste Weg, dies zu tun, ist die Verwendung von new Schlüsselwort.

Dies ist jedoch nicht die beste Methode zum Erstellen neuer Objekte in unseren Testfällen , und verwenden Sie die neue Schlüsselwort macht unsere Tests schwieriger zu lesen und zu warten.

Dieser Blogbeitrag identifiziert die Probleme, die durch das neue Schlüsselwort verursacht werden, und beschreibt, wie wir diese Probleme mithilfe von Factory-Methoden und dem Builder-Muster lösen können.

Neu ist nicht das neue Schwarz

Während dieses Tutorials haben wir einen Komponententest umgestaltet, der sicherstellt, dass registerNewUserAccount(RegistrationForm userAccountData) Methode des RepositoryUserService Die Klasse funktioniert wie erwartet, wenn ein neues Benutzerkonto erstellt wird, indem eine eindeutige E-Mail-Adresse und ein sozialer Anmeldeanbieter verwendet werden.

Das Registrierungsformular class ist ein Data Transfer Object (DTO), und unsere Komponententests setzen ihre Eigenschaftswerte mithilfe von Setter-Methoden. Der Quellcode unseres Unit-Tests sieht wie folgt aus (der relevante Code ist hervorgehoben):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;


@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {

    private static final String REGISTRATION_EMAIL_ADDRESS = "[email protected]";
    private static final String REGISTRATION_FIRST_NAME = "John";
    private static final String REGISTRATION_LAST_NAME = "Smith";
    private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;
    private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;

    private RepositoryUserService registrationService;

    @Mock
    private PasswordEncoder passwordEncoder;

    @Mock
    private UserRepository repository;

    @Before
    public void setUp() {
        registrationService = new RepositoryUserService(passwordEncoder, repository);
    }


    @Test
    public void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException       {
        RegistrationForm registration = new RegistrationForm();
        registration.setEmail(REGISTRATION_EMAIL_ADDRESS);
        registration.setFirstName(REGISTRATION_FIRST_NAME);
        registration.setLastName(REGISTRATION_LAST_NAME);
        registration.setSignInProvider(SOCIAL_SIGN_IN_PROVIDER);

        when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);

        when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {
            @Override
            public User answer(InvocationOnMock invocation) throws Throwable {
                Object[] arguments = invocation.getArguments();
                return (User) arguments[0];
            }
        });

        User createdUserAccount = registrationService.registerNewUserAccount(registration);

        assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());
        assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());
        assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());
        assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());
        assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());
        assertNull(createdUserAccount.getPassword());

        verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);
        verify(repository, times(1)).save(createdUserAccount);
        verifyNoMoreInteractions(repository);
        verifyZeroInteractions(passwordEncoder);
    }
}

Was ist also das Problem? Der hervorgehobene Teil unseres Komponententests ist kurz und relativ einfach zu lesen. Meiner Meinung nach ist das größte Problem dieses Codes, dass er datenzentriert ist. Es erstellt ein neues RegistrationForm -Objekt und legt die Eigenschaftswerte des erstellten Objekts fest, beschreibt jedoch nicht die Bedeutung dieser Eigenschaftswerte.

Wenn wir in der Testmethode neue Objekte erstellen, indem wir die new Schlüsselwort, unsere Tests werden schwieriger zu lesen, weil:

  1. Der Leser muss die verschiedenen Zustände des erstellten Objekts kennen. Wenn wir zum Beispiel an unser Beispiel denken, muss der Leser das wissen, wenn wir ein neues RegistrationForm erstellen -Objekt und legen Sie die Eigenschaftswerte der E-Mail fest , Vorname , Nachname und signInProvider Eigenschaften, bedeutet dies, dass das Objekt eine Registrierung ist, die über einen Social-Sign-In-Anbieter erfolgt.
  2. Wenn das erstellte Objekt viele Eigenschaften hat, verunreinigt der Code, der es erstellt, den Quellcode unserer Tests. Wir sollten daran denken, dass wir uns darauf konzentrieren sollten, das Verhalten der getesteten Methode / Funktion zu beschreiben, obwohl wir diese Objekte in unseren Tests benötigen.

Obwohl es nicht realistisch ist anzunehmen, dass wir diese Nachteile vollständig beseitigen können, sollten wir unser Bestes tun, um ihre Auswirkungen zu minimieren und unsere Tests so einfach wie möglich zu gestalten.

Lassen Sie uns herausfinden, wie wir dies mit Fabrikmethoden erreichen können.

Factory-Methoden verwenden

Wenn wir neue Objekte mit Factory-Methoden erstellen, sollten wir die Factory-Methoden und ihre Methodenparameter so benennen, dass unser Code leichter lesbar und schreibbar ist. Werfen wir einen Blick auf zwei verschiedene Factory-Methoden und sehen wir uns an, welche Auswirkung sie auf die Lesbarkeit unseres Unit-Tests haben.

Der Name der ersten Factory-Methode ist newRegistrationViaSocialSignIn() , und es hat keine Methodenparameter. Nachdem wir diese Factory-Methode zu unserer Testklasse hinzugefügt haben, sieht die Quelle unseres Komponententests wie folgt aus (die relevanten Teile sind hervorgehoben):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;


@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {

	private static final String REGISTRATION_EMAIL_ADDRESS = "[email protected]";
	private static final String REGISTRATION_FIRST_NAME = "John";
	private static final String REGISTRATION_LAST_NAME = "Smith";
	private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;
	private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;

	private RepositoryUserService registrationService;

	@Mock
	private PasswordEncoder passwordEncoder;

	@Mock
	private UserRepository repository;

	@Before
	public void setUp() {
		registrationService = new RepositoryUserService(passwordEncoder, repository);
	}


	@Test
	public void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {
		RegistrationForm registration = newRegistrationViaSocialSignIn();

		when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);

		when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {
			@Override
			public User answer(InvocationOnMock invocation) throws Throwable {
				Object[] arguments = invocation.getArguments();
				return (User) arguments[0];
			}
		});

		User createdUserAccount = registrationService.registerNewUserAccount(registration);

		assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());
		assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());
		assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());
		assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());
		assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());
		assertNull(createdUserAccount.getPassword());

		verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);
		verify(repository, times(1)).save(createdUserAccount);
		verifyNoMoreInteractions(repository);
		verifyZeroInteractions(passwordEncoder);
	}
	
	private RegistrationForm newRegistrationViaSocialSignIn() {
		RegistrationForm registration = new RegistrationForm();
	
		registration.setEmail(REGISTRATION_EMAIL_ADDRESS);
		registration.setFirstName(REGISTRATION_FIRST_NAME);
		registration.setLastName(REGISTRATION_LAST_NAME);
		registration.setSignInProvider(SOCIAL_SIGN_IN_PROVIDER);

		return registration;
	}
}

Die erste Fabrikmethode hat die folgenden Konsequenzen:

  • Der Teil unserer Testmethode, der das neue RegistrationForm erstellt Objekt, ist viel sauberer als zuvor und der Name der Factory-Methode beschreibt den Zustand des erstellten RegistrationForm Objekt.
  • Die Konfiguration unseres Scheinobjekts ist schwerer zu lesen, da der Wert der email Eigentum ist in unserer Fabrikmethode „versteckt“.
  • Unsere Behauptungen sind schwerer zu lesen, da die Eigenschaftswerte des erstellten RegistrationForm Objekt sind in unserer Factory-Methode „versteckt“.
Wenn wir das Objekt-Mutter-Muster verwenden würden, wäre das Problem noch größer, weil wir die zugehörigen Konstanten in die Objekt-Mutter-Klasse verschieben müssten.

Ich denke, es ist fair zu sagen, dass die erste Fabrikmethode zwar ihre Vorteile hat, aber auch ernsthafte Nachteile hat.

Mal sehen, ob die zweite Factory-Methode diese Nachteile beseitigen kann.

Der Name der zweiten Factory-Methode ist newRegistrationViaSocialSignIn() , und es verwendet die E-Mail-Adresse, den Vornamen, den Nachnamen und den Social-Sign-In-Anbieter als Methodenparameter. Nachdem wir diese Factory-Methode zu unserer Testklasse hinzugefügt haben, sieht die Quelle unseres Komponententests wie folgt aus (die relevanten Teile sind hervorgehoben):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;


@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {

	private static final String REGISTRATION_EMAIL_ADDRESS = "[email protected]";
	private static final String REGISTRATION_FIRST_NAME = "John";
	private static final String REGISTRATION_LAST_NAME = "Smith";
	private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;
	private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;

	private RepositoryUserService registrationService;

	@Mock
	private PasswordEncoder passwordEncoder;

	@Mock
	private UserRepository repository;

	@Before
	public void setUp() {
		registrationService = new RepositoryUserService(passwordEncoder, repository);
	}


	@Test
	public void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {
		RegistrationForm registration = newRegistrationViaSocialSignIn(REGISTRATION_EMAIL_ADDRESS,
																REGISTRATION_FIRST_NAME,
																REGISTRATION_LAST_NAME,
																SOCIAL_MEDIA_SERVICE
		);

		when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);

		when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {
			@Override
			public User answer(InvocationOnMock invocation) throws Throwable {
				Object[] arguments = invocation.getArguments();
				return (User) arguments[0];
			}
		});

		User createdUserAccount = registrationService.registerNewUserAccount(registration);

		assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());
		assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());
		assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());
		assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());
		assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());
		assertNull(createdUserAccount.getPassword());

		verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);
		verify(repository, times(1)).save(createdUserAccount);
		verifyNoMoreInteractions(repository);
		verifyZeroInteractions(passwordEncoder);
	}
	
	private RegistrationForm newRegistrationViaSocialSignIn(String emailAddress, String firstName, String lastName, SocialMediaService signInProvider) {
		RegistrationForm registration = new RegistrationForm();
	
		registration.setEmail(emailAddress);
		registration.setFirstName(firstName);
		registration.setLastName(lastName);
		registration.setSignInProvider(signInProvider);

		return registration;
	}
}

Die zweite Factory-Methode hat folgende Konsequenzen:

  • Der Teil unserer Testmethode, der das neue RegistrationForm erstellt Objekt, ist etwas chaotischer als derselbe Code, der die erste Factory-Methode verwendet. Es ist jedoch immer noch sauberer als der ursprüngliche Code, da der Name der Factory-Methode den Zustand des erstellten Objekts beschreibt.
  • Es scheint die Nachteile der ersten Factory-Methode zu eliminieren, da die Eigenschaftswerte des erstellten Objekts nicht innerhalb der Factory-Methode „versteckt“ sind.

Sieht cool aus, oder?

Es wäre wirklich einfach zu glauben, dass im Paradies alles in Ordnung ist, aber das ist nicht der Fall. Obwohl wir gesehen haben, dass Factory-Methoden unsere Tests lesbarer machen können, sind sie nur dann eine gute Wahl, wenn die folgenden Bedingungen erfüllt sind:

  1. Die Fabrikmethode hat nicht zu viele Methodenparameter. Wenn die Anzahl der Methodenparameter wächst, werden unsere Tests schwieriger zu schreiben und zu lesen. Die naheliegende Frage lautet:Wie viele Methodenparameter kann eine Factory-Methode haben? Leider ist es schwierig, eine genaue Antwort auf diese Frage zu geben, aber ich denke, dass die Verwendung einer Factory-Methode eine gute Wahl ist, wenn die Factory-Methode nur eine Handvoll Methodenparameter hat.
  2. Die Testdaten weisen nicht zu viele Schwankungen auf. Das Problem bei der Verwendung von Factory-Methoden besteht darin, dass eine einzelne Factory-Methode typischerweise für einen Anwendungsfall geeignet ist. Wenn wir N Anwendungsfälle unterstützen müssen, brauchen wir N Factory-Methoden. Dies ist ein Problem, da unsere Factory-Methoden mit der Zeit aufgebläht, chaotisch und schwer zu pflegen sind (insbesondere wenn wir das Objektmuttermuster verwenden).

Lassen Sie uns herausfinden, ob Test Data Builder einige dieser Probleme lösen können.

Verwendung von Test Data Buildern

Ein Testdatenersteller ist eine Klasse, die neue Objekte unter Verwendung des Erbauermusters erstellt. Das in Effektives Java beschriebene Builder-Muster hat viele Vorteile, aber unsere Hauptmotivation besteht darin, eine fließende API zum Erstellen der in unseren Tests verwendeten Objekte bereitzustellen.

Wir können eine Test-Data-Builder-Klasse erstellen, die ein neues RegistrationForm erstellt Objekte, indem Sie diesen Schritten folgen:

  1. Erstellen Sie einen RegistrationFormBuilder Klasse.
  2. Fügen Sie ein Registrierungsformular hinzu Feld zur erstellten Klasse. Dieses Feld enthält einen Verweis auf das erstellte Objekt.
  3. Fügen Sie der erstellten Klasse einen Standardkonstruktor hinzu und implementieren Sie ihn, indem Sie ein neues RegistrationForm erstellen Objekt.
  4. Fügen Sie Methoden hinzu, die verwendet werden, um die Eigenschaftswerte des erstellten RegistrationForm festzulegen Objekt. Jede Methode legt den Eigenschaftswert fest, indem sie die richtige Setter-Methode aufruft und einen Verweis auf den RegistrationFormBuilder zurückgibt Objekt. Denken Sie daran, dass die Methodennamen dieser Methoden unsere DSL entweder machen oder brechen können .
  5. Fügen Sie der erstellten Klasse eine build()-Methode hinzu und implementieren Sie sie, indem Sie das erstellte RegistrationForm zurückgeben Objekt.

Der Quellcode unserer Test-Data-Builder-Klasse sieht wie folgt aus:

public class RegistrationFormBuilder {

    private RegistrationForm registration;

    public RegistrationFormBuilder() {
        registration = new RegistrationForm();
    }

    public RegistrationFormBuilder email(String email) {
        registration.setEmail(email);
        return this;
    }

    public RegistrationFormBuilder firstName(String firstName) {
        registration.setFirstName(firstName);
        return this;
    }

    public RegistrationFormBuilder lastName(String lastName) {
        registration.setLastName(lastName);
        return this;
    }

    public RegistrationFormBuilder isSocialSignInViaSignInProvider(SocialMediaService signInProvider) {
        registration.setSignInProvider(signInProvider);
        return this;
    }

    public RegistrationForm build() {
        return registration;
    }
}

Nachdem wir unseren Komponententest geändert haben, um die neue Test Data Builder-Klasse zu verwenden, sieht sein Quellcode wie folgt aus (der relevante Teil ist hervorgehoben):

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {

	private static final String REGISTRATION_EMAIL_ADDRESS = "[email protected]";
	private static final String REGISTRATION_FIRST_NAME = "John";
	private static final String REGISTRATION_LAST_NAME = "Smith";
	private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;
	private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;

	private RepositoryUserService registrationService;

	@Mock
	private PasswordEncoder passwordEncoder;

	@Mock
	private UserRepository repository;

	@Before
	public void setUp() {
		registrationService = new RepositoryUserService(passwordEncoder, repository);
	}


	@Test
	public void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException {
		RegistrationForm registration = new RegistrationFormBuilder()
			.email(REGISTRATION_EMAIL_ADDRESS)
			.firstName(REGISTRATION_FIRST_NAME)
			.lastName(REGISTRATION_LAST_NAME)
			.isSocialSignInViaSignInProvider(SOCIAL_SIGN_IN_PROVIDER)
			.build();

		when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);

		when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {
			@Override
			public User answer(InvocationOnMock invocation) throws Throwable {
				Object[] arguments = invocation.getArguments();
				return (User) arguments[0];
			}
		});

		User createdUserAccount = registrationService.registerNewUserAccount(registration);

		assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());
		assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());
		assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());
		assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());
		assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());
		assertNull(createdUserAccount.getPassword());

		verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);
		verify(repository, times(1)).save(createdUserAccount);
		verifyNoMoreInteractions(repository);
		verifyZeroInteractions(passwordEncoder);
	}
}

Wie wir sehen können, haben Test Data Builder die folgenden Vorteile:

  • Der Code, der neue RegistrationForm-Objekte erstellt, ist sowohl einfach zu lesen als auch zu schreiben. Ich bin ein großer Fan fließender APIs und finde diesen Code sowohl schön als auch elegant.
  • Das Builder-Muster stellt sicher, dass die in unseren Testdaten gefundene Abweichung kein Problem mehr darstellt, da wir der Testdaten-Builder-Klasse einfach neue Methoden hinzufügen können.
  • Die Konfiguration unseres Scheinobjekts und unsere Zusicherungen sind leicht lesbar, da die Konstanten in unserer Testmethode sichtbar sind und unsere DSL die Bedeutung jedes Eigenschaftswerts hervorhebt.

Sollten wir also das Builder-Muster für alles verwenden?

NEIN!

Wir sollten Test Data Builder nur dann verwenden, wenn es sinnvoll ist. Mit anderen Worten, wir sollten sie verwenden, wenn

  1. Wir haben mehr als eine Handvoll Eigenschaftswerte festgelegt.
  2. Unsere Testdaten sind sehr unterschiedlich.

Das Builder-Muster ist eine perfekte Wahl, wenn eine dieser Bedingungen zutrifft. Der Grund dafür ist, dass wir eine domänenspezifische Sprache erstellen können, indem wir die Setter-ähnlichen Methoden der Builder-Klasse benennen. Dadurch sind unsere Tests einfach zu lesen und zu schreiben, selbst wenn wir viele verschiedene Objekte erstellen und viele Eigenschaftswerte festlegen müssten.

Das ist die Stärke des Builder-Musters.

Das ist alles für heute. Fahren wir fort und fassen zusammen, was wir aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Wir haben gelernt, warum es eine schlechte Idee ist, Objekte in der Testmethode mit new zu erstellen Schlüsselwort, und wir haben zwei verschiedene Möglichkeiten kennengelernt, die Objekte zu erstellen, die in unseren Tests verwendet werden.

Genauer gesagt hat uns dieser Blogpost drei Dinge gelehrt:

  • Es ist keine gute Idee, die erforderlichen Objekte in der Testmethode mit Hilfe von new zu erstellen Schlüsselwort, weil es unsere Tests unordentlich und schwer lesbar macht.
  • Wenn wir nur eine Handvoll Eigenschaftswerte festlegen müssen und unsere Testdaten nicht viele Variationen aufweisen, sollten wir das erforderliche Objekt mithilfe einer Factory-Methode erstellen.
  • Wenn wir viele Eigenschaftswerte festlegen müssen und/oder unsere Testdaten viele Variationen aufweisen, sollten wir das erforderliche Objekt mithilfe eines Testdatengenerators erstellen.

Java-Tag