如何使用Spring Boot + Spring Data JPA对悲观锁定进行单元测试

ysl*_*ysl 7 java unit-testing spring-data-jpa spring-boot

我想测试是否FooRepository.lock()有人工作,有人打电话给lock(),其他人打电话给它应该等待.

以下是我最好的尝试,它不起作用.我相信原因是entityManger并且fooRepository正在参与同一笔交易.

如何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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

class 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

class FooRepository:

package com.example.demo;

import java.util.UUID;

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

public interface FooRepository extends JpaRepository<Foo, UUID>, FooRepositoryCustom {  
}
Run Code Online (Sandbox Code Playgroud)

class FooRepositoryCustom:

package com.example.demo;

public interface FooRepositoryCustom {  
    public void lock(Foo foo);  
}
Run Code Online (Sandbox Code Playgroud)

class 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);
    }   
}
Run Code Online (Sandbox Code Playgroud)

Gho*_*ica 1

您的单元测试错误

您不必编写单元测试来练习某些第三方框架实现的功能。单元测试适用于您的单元!

换句话说:您不需要验证锁定是否按预期工作。你的单位做:

entityManager.lock(foo, LockModeType.PESSIMISTIC_WRITE);
Run Code Online (Sandbox Code Playgroud)

因此,您可以考虑在这里进行测试的唯一事情:确保lock()使用预期参数调用实体管理器方法。

含义:验证您的代码确实使用了您认为应该使用的框架 - 但不要测试其他人的代码!你看,当你的单元测试显示框架是错误的时你会怎么做......你无法改变这一点!(当然,你可以写一个错误报告)

免责声明:在特殊情况下,您可能会假设某些第 3 方产品存在错误 - 那么编写单元测试来测试此假设可能非常有用。这样您就可以稍后针对该产品的新版本运行单元测试,以查看错误是否仍然存在。