簡體   English   中英

如何使用 Spring Boot + Spring Data JPA 對悲觀鎖定進行單元測試

[英]How to unit test pessimistic locking with Spring Boot + Spring Data JPA

我想測試FooRepository.lock()是否有效,在有人調用lock()之后,其他人調用它應該等待。

以下是我最好的嘗試,它不起作用。 我相信原因是entityMangerfooRepository都參與了同一個事務。

如何從另一個事務中調用lock() 或者對悲觀鎖進行單元測試的任何建議? 謝謝!!

FooRepositoryTest:

package com.example.demo;

import java.util.UUID;

import javax.persistence.LockModeType;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
public class FooRepositoryTest {

    @Autowired
    private TestEntityManager entityManager;    

    @Autowired
    private FooRepository fooRepository;

    @Test
    public void lockTest() {
        // given
        Foo foo = new Foo();
        foo.setName("foo-name");

        UUID fooId = fooRepository.save(foo).getFooId();
        entityManager.flush();
        entityManager.clear();

        // when
        Foo savedFoo = fooRepository.findOne(fooId);
        fooRepository.lock(savedFoo);

        // then
        // I want something like this to be lock wait,
        // something to confirm the above fooRepository.lock() work
        entityManager.getEntityManager().lock(savedFoo, LockModeType.PESSIMISTIC_WRITE);
    }

}

Foo類:

package com.example.demo;

import java.util.UUID;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Foo {  
    @Id
    @GeneratedValue
    private UUID fooId;

    private String name;

    public UUID getFooId() {
        return fooId;
    }

    public void setFooId(UUID fooId) {
        this.fooId = fooId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

FooApplication 類:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FooApplication {

    public static void main(String[] args) {
        SpringApplication.run(FooApplication.class, args);
    }
}

類 FooRepository:

package com.example.demo;

import java.util.UUID;

import org.springframework.data.jpa.repository.JpaRepository;

public interface FooRepository extends JpaRepository<Foo, UUID>, FooRepositoryCustom {  
}

類 FooRepositoryCustom:

package com.example.demo;

public interface FooRepositoryCustom {  
    public void lock(Foo foo);  
}

FooRepositoryImpl 類:

package com.example.demo;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;

import org.springframework.beans.factory.annotation.Autowired;

public class FooRepositoryImpl implements FooRepositoryCustom {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void lock(Foo foo) {
        entityManager.lock(foo, LockModeType.PESSIMISTIC_WRITE);
    }   
}

你得到錯誤的單元測試。

不會編寫單元測試來執行某些 3rd 方框架實現的功能。 單元測試適用於您的單元!

換句話說:您不需要驗證鎖定是否按預期工作。 您的單位可以:

entityManager.lock(foo, LockModeType.PESSIMISTIC_WRITE);

所以你可以考慮在這里測試的唯一一件事:確保使用預期的參數調用實體管理器lock()方法。

含義:驗證您的代碼確實使用了您認為應該使用的框架 - 但不要測試其他人的代碼! 你看 - 當你的單元測試表明框架是錯誤的時你會怎么做......你不能改變它! (當然,你可以寫一個錯誤報告然后)

免責聲明:在某些特殊情況下,您可能會假設某些 3rd 方產品存在錯誤 - 那么編寫單元測試來測試此假設可能非常有用。 這樣您以后就可以針對該產品的新版本運行單元測試,以查看錯誤是否仍然存在。

使用集成測試測試悲觀鎖定處理很重要(我可以說是強制性的嗎?),原因有兩個:

  • LockTimeout 參數很可能沒有正確配置(Oracle 和 PostgreSQL 默認為無限時間),這可能會對生產中系統的穩定性/性能產生巨大影響;
  • 大多數 RDBMS 對悲觀鎖定的 JPA 實現非常有限,因為 6 個內部 LockTimeout 參數不同; 僅針對內存數據庫進行測試是不夠的,需要特別考慮。

在博客文章使用 SpringBoot 和 JPA 測試悲觀鎖定處理中,您可以:

  • 閱讀有關悲觀鎖定處理的更多信息;
  • 您可以在GitHub 上找到針對 Oracle、PostgreSQL、MySQL 和 Apache Derby 進行測試的示例

🔔 Spring 框架僅用作示例。 您可以輕松地為每個其他框架調整測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM