Wie testen Sie Spring @Transactional, ohne nur zu schlagen, hibernate level-1-cache oder mache ein manuelles session flush?

Mit Spring + Hibernate und transactional-Annotationen.

Ich versuche zum test das folgende:

  1. eine Methode aufrufen, die änderungen, die ein User-Objekt ruft dann eine @Transactional service-Methode beibehalten, es
  2. gelesen das Objekt wieder aus der DB und sicherzustellen, dass es die Werte sind richtig, nach der Methode

Das erste problem, das ich hatte, war zu Lesen, das User-Objekt in Schritt 2 zurück, die man in der Hibernate-level-1-cache und wird nicht tatsächlich aus der Datenbank gelesen.

Ich daher manuell entfernt das Objekt aus dem cache mit der Sitzung zu zwingen, die aus der Datenbank gelesen. Allerdings, wenn ich dies tun, wird die Objekt-Werte sind niemals persistent im Gerät zu testen (ich weiß, er rollt wieder, nachdem der test abgeschlossen ist, weil die Einstellungen, die ich angegeben).

Ich habe versucht manuell Spülen der Sitzung nach Aufruf der @Transactional service-Methode, und die, die es TATEN, übernehmen Sie die änderungen. Doch das war nicht was ich erwartet habe. Ich dachte, dass @Transactional service-Methode würde versichern die Transaktion ein commit ausgeführt wurde und die session geleert, bevor es zurückgegeben.
Ich weiß, im Allgemeinen das Frühjahr wird entscheiden, Wann dies zu tun, management, aber ich dachte, die "unit of work" in @Transactional Methode war die Methode.

In jedem Fall, jetzt versuche ich herauszufinden, wie ich den test ein @Transactional Methode im Allgemeinen.

Hier ist eine junit-Testmethode, die fehlschlägt:

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@TransactionConfiguration(transactionManager = "userTransactionManager", defaultRollback = true)
@WebAppConfiguration()
@ContextConfiguration(locations = { "classpath:test-applicationContext.xml",
        "classpath:test-spring-servlet.xml",
        "classpath:test-applicationContext-security.xml" })
public class HibernateTest {

    @Autowired
    @Qualifier("userSessionFactory")
    private SessionFactory sessionFactory;

    @Autowired
    private UserService userService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private QueryService queryService;

    @Autowired
    private NodeService nodeService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private UserContext userContext;

  @Test
    public void testTransactions() {
        //read the user
        User user1 = userService.readUser(new Long(77));
        //change the display name
        user1.setDisplayName("somethingNew");
        //update the user using service method that is marked @Transactional
        userService.updateUserSamePassword(user1);
        //when I manually flush the session everything works, suggesting the
        //@Transactional has not flushed it at the end of the method marked
        //@Transactional, which implies it is leaving the transaction open?
        //session.flush();
        //evict the user from hibernate level 1 cache to insure we are reading
        //raw from the database on next read
        sessionFactory.getCurrentSession().evict(user1);
        //try to read the user again
        User user2 = userService.readUser(new Long(77));
        System.out.println("user1 displayName is " + user1.getDisplayName());
        System.out.println("user2 displayName is " + user2.getDisplayName());
        assertEquals(user1.getDisplayName(), user2.getDisplayName());
    }
}

Wenn ich manuell Spülen Sie die session, dann ist der test erfolgreich ist. Allerdings hätte ich erwartet, dass die @Transactional Methode, um Sorgfalt zu Begehen und Spülung der Sitzung.

Die service-Methode für updateUserSamePassword ist hier:

@Transactional("userTransactionManager")
@Override
public void updateUserSamePassword(User user) {
    userDAO.updateUser(user);
}

Die DAO-Methode ist hier:

@Override
public void updateUser(User user) {
    Session session = sessionFactory.getCurrentSession();
    session.update(user);
}

SesssionFactory ist autowired:

@Autowired
@Qualifier("userSessionFactory")
private SessionFactory sessionFactory;

Ich bin mit der XML-Anwendung, die Kontext-Konfiguration. Ich habe:

<context:annotation-config />
<tx:annotation-driven transaction-manager="userTransactionManager" />

Und

<bean id="userDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
    <property name="driverClass" value="${user.jdbc.driverClass}"/>
    <property name="jdbcUrl" value="${user.jdbc.jdbcUrl}" />
    <property name="user" value="${user.jdbc.user}" />
    <property name="password" value="${user.jdbc.password}" />
    <property name="initialPoolSize" value="3" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="17" />
</bean>

<bean id="userSessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="userDataSource" />
    <property name="configLocation" value="classpath:user.hibernate.cfg.xml" />
</bean>

<bean id="userTransactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="dataSource" ref="userDataSource" />
    <property name="sessionFactory" ref="userSessionFactory" />
</bean>

Gibt es auch eine Komponente, scan auf die Dienste und dao-Klassen. Wie gesagt, das ist eine Arbeit in der Produktion.

Dachte ich, dass wenn ich eine Methode gekennzeichnet @Transactional dass am Ende der Methode (z.B. die update-Methode hier), Frühling wäre gezwungen, die Sitzung zu Begehen und bündig.

Kann ich sehen, nur ein paar Optionen:

  1. Ich etwas falsch konfiguriert, obwohl dies funktioniert für mich im Allgemeinen (nicht nur der unit-tests). Irgendwelche Vermutungen? Irgendwelche Ideen, wie man dies testen?

  2. Etwas über das unit-test-config sich nicht verhält, die Art und Weise der app.

  3. Transaktionen und Sitzungen, die nicht so arbeiten. Mein einziger Abzug ist, dass der Frühling ist die Transaktion verlassen wird und/oder die session öffnen nach dem aufrufen der update-Methode. Also, wenn ich Sie manuell entfernen Sie die Benutzer, die auf das Session-Objekt, die diese änderungen noch nicht festgeschrieben wurden noch.

Kann jemand bestätigen, ob dies ist das erwartete Verhalten? Sollte nicht @Transaction gezwungen Begehen und bündig auf Sitzung? Wenn nicht, wie würde dann ein test-eine Methode gekennzeichnet @Transactional und dass die Methoden, die eigentlich die Arbeit mit Transaktionen?

I. e., wie soll ich umschreiben, mein Unit-test hier?

Irgendwelche anderen Ideen?

InformationsquelleAutor user2166452 | 2014-10-27
Schreibe einen Kommentar