Frage

wir sind mit Feder für meine Anwendungszwecke und Spring Testing Framework für Unit-Tests. Wir haben ein kleines Problem aber: der Anwendungscode lädt einen Spring-Anwendungskontext aus einer Liste von Orten (XML-Dateien) in dem Classpath. Aber wenn wir unsere Unit-Tests laufen, wollen wir einige der Frühling Bohnen statt vollwertiger Implementierungsklassen verspottet werden. Darüber hinaus für einige Unit-Tests wollen wir ein paar Bohnen verspottet werden, während für andere Einheit Tests, die wir andere Bohnen wollen Mocks werden, wie wir verschiedene Schichten der Anwendung testen.

All dies bedeutet, dass ich bestimmte Bohnen des Anwendungskontextes und aktualisieren Sie den Kontext neu definiert werden soll, wenn gewünscht. Während dies zu tun, ich will nur einen kleinen Teil der Bohnen in einem (oder mehreren) Original xml Bohnen Definitionsdatei befindet sich neu zu definieren. Ich kann nicht eine einfache Möglichkeit, es zu tun finden. Es ist immer angesehen, dass Frühling eine Einheit Prüfung freundliche Rahmen ist so ich hier etwas fehlt werden muss.

Haben Sie irgendwelche Ideen haben, wie es zu tun?

Danke.

War es hilfreich?

Lösung

ich würde eine benutzerdefinierte Testclass und einige einfache Regeln für die Standorte der Feder bean.xml vorschlagen

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:spring/*.xml",
    "classpath*:spring/persistence/*.xml",
    "classpath*:spring/mock/*.xml"})
@Transactional
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware 
{

    /**
     * Logger for Subclasses.
     */
    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    /**
     * The {@link ApplicationContext} that was injected into this test instance
     * via {@link #setApplicationContext(ApplicationContext)}.
     */
    protected ApplicationContext applicationContext;

    /**
     * Set the {@link ApplicationContext} to be used by this test instance,
     * provided via {@link ApplicationContextAware} semantics.
     */
    @Override
    public final void setApplicationContext(
            final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

, wenn es Mock-bean.xml in der angegebenen Position sind, werden sie alle „echten“ bean.xml in den „normalen“ Stellen außer Kraft setzen - Ihre normalen Stellen könnten abweichen

aber ... ich würde nie Mock und nicht-mock Bohnen mischen es ist schwer, Probleme zu verfolgen, wenn die Anwendung älter wird.

Andere Tipps

Einer der Gründe Feder als Testfreundlich beschrieben wird, ist, weil es einfach sein kann, nur neue oder Mock Sachen in dem Unit-Test.

Alternativ haben wir die folgende Konfiguration mit großem Erfolg eingesetzt, und ich denke, es ist ganz in der Nähe ist, was Sie wollen, ich würde stark empfehlen es:

Für alle Bohnen, die verschiedenen Implementierungen in unterschiedlichen Kontexten müssen, wechseln Sie zu Annotation basierend Verkabelung. Sie können die anderen verlassen, wie sie ist.

Implementieren Sie den folgenden Satz von Anmerkungen

 <context:component-scan base-package="com.foobar">
     <context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
     <context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
 </context:component-scan>

Dann kommentieren Sie Ihre leben Implementierungen mit @Repository, Ihre Stummel Implementierungen mit @StubRepository, beliebigen Code, der mit @TestScopedComponent in der Einheit-Testvorrichtung nur vorhanden sein sollte . Sie können in benötigen noch ein paar Anmerkungen laufen, aber diese sind ein guter Start.

Wenn Sie eine Menge von spring.xml haben, müssen Sie wahrscheinlich ein paar neue Frühjahr XML-Dateien machen, die im Grunde nur die Komponente-Scan-Definitionen enthalten. Sie würden normalerweise nur diese Dateien auf Ihrem normalen @ContextConfiguration Liste anhängen. Der Grund dafür ist, dass Sie häufig mit unterschiedlichen Konfigurationen des Kontext-Scans (glauben Sie mich am Ende, Sie wird mindestens 1 weitere Anmerkungen machen, wenn Sie Web-Tests tun, die für 4 macht relevante Kombinationen)

Dann nutzen Sie im Grunde die

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
Hinweis

, dass dieses Setup funktioniert nicht können Sie abwechselnd Kombinationen von Stub / Live-Daten haben. Wir haben versucht, diese, und ich denke, dass in einem Chaos geführt würde ich niemandem empfehlen;) Wir entweder Draht inn der volle Satz von Stubs oder die vollständige Reihe von Live-Dienste

.

Wir vor allem Auto-verdrahtet Stub Abhängigkeiten verwenden, wenn gui in der Nähe von Sachen zu testen, wo die Abhängigkeiten sind in der Regel ganz erheblich. In cleanen Bereichen des Codes verwenden wir mehr reguläre Komponententests.

In unserem System haben wir die folgenden XML-Dateien für die Komponenten-Scan:

  • für regelmäßige Web-Produktion
  • für Startbahn mit Stubs nur
  • für Integrationstests (in junit)
  • für Unit-Tests (in junit)
  • für Selen Web-Tests (in junit)

Das bedeutet, dass wir insgesamt 5 verschiedene systemweite Konfigurationen haben, dass wir die Anwendung mit beginnen können. Da wir nur Anmerkungen verwenden, ist der Frühling schnell genug, um auch diese Unit-Tests autowire wir verdrahtet werden sollen. Ich weiß, das ist nicht traditionelles, aber es ist wirklich toll.

Ohne Integrationstests mit voller Live-Setup ausführen, und ein- oder zweimal habe ich beschlossen, bekommen wirklich pragmatisch und wollen eine 5 Live-Verdrahtungen und eine einzige Mock haben:

public class HybridTest {
   @Autowired
   MyTestSubject myTestSubject;


   @Test
   public void testWith5LiveServicesAndOneMock(){
     MyServiceLive service = myTestSubject.getMyService();
     try {
          MyService mock = EasyMock.create(...)
          myTestSubject.setMyService( mock);

           .. do funky test  with lots of live but one mock object

     } finally {
          myTestSubject.setMyService( service);
     }


   }
}

Ich weiß, dass der Test Puristen all dies über mir sein werden. Aber manchmal ist es nur eine sehr pragmatische Lösung, die sehr elegant sein, stellt sich heraus, wenn die Alternative wirklich wirklich hässlich wäre. Wieder ist es in der Regel in diesen gui nahen Bereichen.

Sehen Sie diese Tutorial mit @InjectedMock Annotation

Es hat mich gerettet viel Zeit. Sie verwenden nur

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

und alle Probleme gelöst sind. Mockito wird die Feder Dependency Injection mit einem Mock ersetzen. Früher habe ich nur es selbst und es funktioniert super.

Es gibt einige sehr komplizierte und leistungsfähige Lösungen hier aufgelistet.

Aber es gibt eine FAR FAR einfacher Art und Weise zu erreichen, was Stas gefragt hat, was bedeutet nichts anderes als eine Zeile Code in der Testmethode zu ändern. Es funktioniert für Unit-Tests und Spring Integrationstests gleichermaßen für autowired Abhängigkeiten, private und geschützte Felder aus.

Hier ist sie:

junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);

Sie können auch Ihre Unit-Tests schreiben, um keine Lookups überhaupt benötigen:

@ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {

    @Autowired
    private MyBean myBean; // the component under test

    @Test
    public void testMyBean() {
        ...
    }
}

Das gibt eine einfache Möglichkeit, echte Konfigurationsdateien mit Testkonfigurationsdateien zu mischen und anzupassen.

Wenn zum Beispiel Hibernate, könnte ich meine session Bohne in einer Konfigurationsdatei (verwendet wird sowohl in den Tests und die Haupt app) habe, und habe von Datasource-Bean in einer anderen Konfigurationsdatei (man könnte eine DriverManagerDataSource verwenden, um ein in-Memory-db, könnte die andere einen JNDI-Lookup verwenden).

Aber auf jeden Fall beherzigen @ cletus die Warnung; -)

Einfach. Sie verwenden einen benutzerdefinierten Anwendungskontext für die Komponententests. Oder Sie verwenden Sie nicht ein überhaupt und Sie manuell erstellen und injizieren Ihre Bohnen.

Es klingt für mich wie Ihre Tests könnten ein bisschen zu weit gefasst sein. Unit-Tests sind über das Testen, na ja, Einheiten. Ein Spring-Bean ist ein ziemlich gutes Beispiel für eine Einheit. Sie sollten nicht einen gesamten Anwendungskontext dafür brauchen. Ich finde, dass, wenn Ihre Unit-Tests so hohe Niveau, dass Sie Hunderte von Bohnen benötigen, Datenbankverbindungen, etc dann Sie eine wirklich fragile Einheit Test haben, der auf der nächsten Änderung brechen wird, schwer zu halten und wirklich isn‘ t Hinzufügen viel Wert.

Sie können über die Import Funktion in Ihr Test-App Kontext in den prod Bohnen zu laden und die, die Sie wollen, außer Kraft setzen. Zum Beispiel ist meine prod Datenquelle in der Regel über JNDI Lookup erworben, aber wenn ich teste, verwende ich eine Driverdatenquelle, damit ich den App-Server starten muß, um nicht zu testen.

Ich habe nicht die Rating-Punkte haben Antwort auf Stapel auf duffymo, aber ich wollte nur in läuten und sagen, sein war die „richtige“ Antwort für mich.

Instanziieren eine FileSystemXmlApplicationContext in Ihrem Gerät-Test-Setup mit einem benutzerdefinierten applicationContext.xml. In dieser benutzerdefinierten xml, an der Spitze, tut ein als duffymo anzeigt. Dann erklären Sie Ihre Mock Bohnen, nicht-JNDI Datenquellen, etc, dass die ID des in den Import deklariert wird außer Kraft setzen.

Arbeitete wie ein Traum für mich.

Sie müssen keine Test Kontexten verwendet werden (keine Rolle spielt ist XML oder Java-basiert). Seit dem Frühjahr Boot 1.4 ist verfügbar neue Anmerkung @MockBean die native Unterstützung eingeführt für spöttisch und Ausspionieren von Spring Beans.

Vielleicht könnten Sie Qualifikation für Ihre Bohnen verwenden? Sie würden neu definieren die Bohnen Sie in einem separaten Anwendungskontext verspotten wollen und sie mit einem Qualifier „test“ beschriften. In Ihren Unit-Tests, wenn Sie Ihre Bohnen Verdrahtung immer die Qualifikation „test“ geben Sie die Mock-ups zu verwenden.

Ich will das Gleiche tun, und wir finden es wichtig.

Der derzeitige Mechanismus wir benutzen, ist ziemlich Handbuch, aber es funktioniert.

Sagen Sie zum Beispiel, Sie wollen Y. verspotten Bohne vom Typ Was wir tun, jede Bohne ist, dass diese Abhängigkeit hat wir eine Schnittstelle machen implementieren - „IHasY“. Diese Schnittstelle ist

interface IHasY {
   public void setY(Y y);
}

Dann in unserem Test haben wir die util-Methode aufrufen ...

 public static void insertMock(Y y) {
        Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
        for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
            IHasY invoker = (IHasY) iterator.next();
            invoker.setY(y);
        }
    }

Ich will nicht eine ganze XML-Datei erstellen, diese neue Abhängigkeit zu injizieren, und das ist, warum ich das mag.

Wenn Sie bereit sind, eine XML-Konfigurationsdatei dann die Art und Weise zu schaffen wäre zu gehen eine neue Fabrik mit den Pseudo-Bohnen zu erstellen und Ihre Standard-Fabrik ein Elternteil dieser Fabrik machen. Stellen Sie sicher, dass Sie dann von der neuen Kind Fabrik alle Bohnen laden. Wenn dies tun die Unter Fabrik werden die Bohnen im Stammwerk außer Kraft setzen, wenn die Bohne IDs die gleichen sind.

Wenn nun in meinem Test, Wenn ich könnte programmatisch eine Fabrik schaffen, das wäre genial. Mit XML zu verwenden ist einfach zu umständlich. Ich suche das Kind Fabrik mit Code zu erstellen. Dann kann jeder Test seine Fabrik, um die Art und Weise konfiguriert es will. Es gibt keinen Grund, warum ein Werk wie das wird nicht funktionieren.

feder reinject ist so konzipiert, Bohnen mit Mocks zu ersetzen.

Da die OP dies kommen: Springockito

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top