Wir haben eine Reihe von JUnit-Testfällen (Integrationstests), die logisch in verschiedene Testklassen gruppiert sind.
Wir können den Spring-Anwendungskontext einmal pro Testklasse laden und für alle Testfälle in einer JUnit-Testklasse wiederverwenden, wie unter http://static.springsource.org/spring/docs/current/spring-framework-reference angegeben /html/testing.html
Wir haben uns jedoch nur gefragt, ob es eine Möglichkeit gibt, den Spring-Anwendungskontext für eine Reihe von JUnit-Testklassen nur einmal zu laden.
FWIW, wir verwenden Spring 3.0.5, JUnit 4.5 und verwenden Maven, um das Projekt zu erstellen.
spring
junit
junit4
spring-test
Ramesh
quelle
quelle
Antworten:
Ja, das ist durchaus möglich. Sie müssen lediglich dasselbe
locations
Attribut in Ihren Testklassen verwenden:@ContextConfiguration(locations = "classpath:test-context.xml")
Spring speichert Anwendungskontexte nach
locations
Attributen zwischen. Wenn derselbelocations
zum zweiten Mal angezeigt wird, verwendet Spring denselben Kontext, anstatt einen neuen zu erstellen.Ich habe einen Artikel über diese Funktion geschrieben: Beschleunigen von Spring-Integrationstests . Außerdem wird dies in der Spring-Dokumentation ausführlich beschrieben: 9.3.2.1 Kontextverwaltung und Caching .
Dies hat eine interessante Bedeutung. Da Spring nicht weiß, wann JUnit fertig ist, wird der gesamte Kontext für immer zwischengespeichert und mit dem JVM-Shutdown-Hook geschlossen. Dieses Verhalten (insbesondere wenn Sie viele Testklassen mit unterschiedlichen haben
locations
) kann zu übermäßiger Speichernutzung, Speicherlecks usw. führen. Ein weiterer Vorteil des Caching-Kontexts.quelle
Um die Antwort von Tomasz Nurkiewicz zu ergänzen , kann ab Frühjahr 3.2.2 die
@ContextHierarchy
Annotation verwendet werden, um eine separate, zugeordnete Mehrfachkontextstruktur zu haben. Dies ist hilfreich, wenn mehrere Testklassen (z. B.) speicherinterne Datenbank-Setups (Datenquelle, EntityManagerFactory, TX-Manager usw.) gemeinsam nutzen möchten.Zum Beispiel:
@ContextHierarchy({ @ContextConfiguration("/test-db-setup-context.xml"), @ContextConfiguration("FirstTest-context.xml") }) @RunWith(SpringJUnit4ClassRunner.class) public class FirstTest { ... } @ContextHierarchy({ @ContextConfiguration("/test-db-setup-context.xml"), @ContextConfiguration("SecondTest-context.xml") }) @RunWith(SpringJUnit4ClassRunner.class) public class SecondTest { ... }
Mit diesem Setup wird der Kontext, der "test-db-setup-context.xml" verwendet, nur einmal erstellt, aber die darin enthaltenen Beans können in den Kontext einzelner Komponententests eingefügt werden
Mehr zum Handbuch: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#testcontext-ctx-management (Suche nach " Kontexthierarchie ")
quelle
Grundsätzlich ist spring intelligent genug, um dies für Sie zu konfigurieren, wenn Sie dieselbe Anwendungskontextkonfiguration für die verschiedenen Testklassen haben. Angenommen, Sie haben zwei Klassen A und B wie folgt:
@ActiveProfiles("h2") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class A { @MockBean private C c; //Autowired fields, test cases etc... } @ActiveProfiles("h2") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class B { @MockBean private D d; //Autowired fields, test cases etc... }
In diesem Beispiel verspottet Klasse A Bean C, während Klasse B Bean D verspottet. Spring betrachtet diese also als zwei verschiedene Konfigurationen und lädt daher den Anwendungskontext einmal für Klasse A und einmal für Klasse B.
Wenn wir stattdessen möchten, dass spring den Anwendungskontext zwischen diesen beiden Klassen teilt, müssten sie wie folgt aussehen:
@ActiveProfiles("h2") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class A { @MockBean private C c; @MockBean private D d; //Autowired fields, test cases etc... } @ActiveProfiles("h2") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class B { @MockBean private C c; @MockBean private D d; //Autowired fields, test cases etc... }
Wenn Sie Ihre Klassen so verkabeln, lädt spring den Anwendungskontext nur einmal für Klasse A oder B, je nachdem, welche Klasse unter den beiden zuerst in der Testsuite ausgeführt wird. Dies kann über mehrere Testklassen hinweg repliziert werden. Das einzige Kriterium ist, dass Sie die Testklassen nicht anders anpassen sollten. Jede Anpassung, die dazu führt, dass sich die Testklasse (in den Augen des Frühlings) von der anderen unterscheidet, würde bis zum Frühjahr einen anderen Anwendungskontext schaffen.
quelle
Erstellen Sie Ihre Konfigurationsklasse wie unten
@ActiveProfiles("local") @RunWith(SpringJUnit4ClassRunner.class ) @SpringBootTest(classes ={add your spring beans configuration classess}) @TestPropertySource(properties = {"spring.config.location=classpath:application"}) @ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) public class RunConfigration { private ClassLoader classloader = Thread.currentThread().getContextClassLoader(); private static final Logger LOG = LoggerFactory.getLogger(S2BXISINServiceTest.class); //auto wire all the beans you wanted to use in your test classes @Autowired public XYZ xyz; @Autowired public ABC abc; } Create your test suite like below @RunWith(Suite.class) @Suite.SuiteClasses({Test1.class,test2.class}) public class TestSuite extends RunConfigration { private ClassLoader classloader = Thread.currentThread().getContextClassLoader(); private static final Logger LOG = LoggerFactory.getLogger(TestSuite.class); }
Erstellen Sie Ihre Testklassen wie unten
public class Test1 extends RunConfigration { @Test public void test1() { you can use autowired beans of RunConfigration classes here } } public class Test2a extends RunConfigration { @Test public void test2() { you can use autowired beans of RunConfigration classes here } }
quelle
Ein bemerkenswerter Punkt ist, dass
use @MockBean in different test classes
Spring , wenn wir @SpringBootTests verwenden, den Anwendungskontext nicht für alle Tests wiederverwenden kann.Die Lösung ist
to move all @MockBean into an common abstract class
und das behebt das Problem.@SpringBootTests(webEnvironment = WebEnvironment.RANDOM_PORT, classes = Application.class) public abstract class AbstractIT { @MockBean private ProductService productService; @MockBean private InvoiceService invoiceService; }
Dann können die Testklassen wie folgt gesehen werden
public class ProductControllerIT extends AbstractIT { // please don't use @MockBean here @Test public void searchProduct_ShouldSuccess() { } } public class InvoiceControllerIT extends AbstractIT { // please don't use @MockBean here @Test public void searchInvoice_ShouldSuccess() { } }
quelle