当前位置:优学网  >  在线题库

Junit导致@ParameterizedTest失败的奇怪行为

发表时间:2022-07-21 00:41:10 阅读:76

我有一个非常简单的测试用例,具有最基本的设置:

@Entity
public class Tags {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(unique = true)
  private String name;

  public Tags(String name) {
    this.name = name;
  }
}

@Repository
public interface TagsRepository extends JpaRepository<Tags, Integer> {}

测试设置:

@DataJpaTest
public class TagsTest implements WithAssertions {

  @Autowired
  private TagsRepository tagsRepo;

  @BeforeEach
  void setUp() {
    Tags tag1 = new Tags("tag1");
    Tags tag2 = new Tags("tag2");
    Tags tag3 = new Tags("tag3");

    tagsRepo.saveAll(List.of(tag1, tag2, tag3));
  }

  @AfterEach
  void cleanUp() {
    tagsRepo.deleteAll();
  }

  @Test
  void test() {
    Tags actual1 = tagsRepo.findById(1).orElse(null);
    assertThat(actual1).isNotNull();  // <- passed
  }

  @Test
  void test2() {
    Tags actual2 = tagsRepo.findById(1).orElse(null);
    assertThat(actual2).isNotNull();  // <- failed
  }

  @Test
  void test3() {
    Tags actual3 = tagsRepo.findById(2).orElse(null);
    assertThat(actual3).isNotNull();  // <- failed
  }
}

意外行为:

当整体运行"测试类"时,只有第一个测试通过,第二个和第三个测试都失败.

这也导致了`@ParameterizedTest中的问题:

@ParameterizedTest
@ValueSource(ints = { 1, 1, 2 }) // <- second and third test failed
void test4(Integer id) {
  Tags actual = tagsRepo.findById(id).orElse(null);
  assertThat(actual).isNotNull();
}

将数据源更改为@MethodSource@CsvSource后的行为相同.

我试图在每次测试中初始化数据,但同样的事情发生了:

@Test
void test() {
  Tags tag1 = new Tags("tag1");
  Tags tag2 = new Tags("tag2");
  Tags tag3 = new Tags("tag3");

  tagsRepo.saveAll(List.of(tag1, tag2, tag3));

  Tags actual1 = tagsRepo.findById(1).orElse(null);

  assertThat(actual1).isNotNull();

  tagsRepo.deleteAll();
}

为什么只有第一个测试通过,而随后的测试失败?我试着使用传入的id的不同组合.但都是一样的行为.

通过这个简单的演示,我得出结论,运行类似的测试会引发问题,即使测试不应该相互影响?

我知道我不应该立即测试SpringBoot提供的内置API,但这是我在使用@参数化测试带有多个参数的mybatis时发现的问题.

编辑:似乎大多数人都试图通过[在每次测试之前重新创建数据库]来解决这个问题(https://stackoverflow.com/questions/34617152/how-to-re-create-database-before-each-test-in-spring/67262467#67262467)

🎖️ 优质答案
  • 它不起作用,因为每次您在setUp()方法中删除/保存数据时,ID的计数器都会继续运行:

    @BeforeEach
      void setUp() {
        Tags tag1 = new Tags("tag1");
        Tags tag2 = new Tags("tag2");
        Tags tag3 = new Tags("tag3");
    
        tagsRepo.saveAll(List.of(tag1, tag2, tag3));
      }
    

    对于第一次测试,您将有:

    tag1-> id = 1
    tag2-> id = 2
    tag3-> id = 3
    

    但对于第二个,您将拥有:

    tag1-> id = 4
    tag2-> id = 5
    tag3-> id = 6
    

    等等正确的方法是保存每个变量并保存在类级变量中,如下所示:

    @DataJpaTest
    public class TagsTest implements WithAssertions {
    
        @Autowired
        private TagsRepository tagsRepo;
    
        private Tags tag1;
        private Tags tag2;
        private Tags tag3;
    
        @BeforeEach
        void setUp() {
            tag1 = tagsRepo.save(new Tags("tag1"));
            tag2 = tagsRepo.save(new Tags("tag2"));
            tag3 = tagsRepo.save(new Tags("tag3"));
        }
    
        @AfterEach
        void cleanUp() {
            tagsRepo.deleteAll();
        }
    
        @Test
        void test() {
            Tags actual1 = tagsRepo.findById(tag1.getId()).orElse(null);
            assertThat(actual1).isNotNull();
        }
    
        @Test
        void test2() {
            Tags actual2 = tagsRepo.findById(tag1.getId()).orElse(null);
            assertThat(actual2).isNotNull();
        }
    
        @Test
        void test3() {
            Tags actual3 = tagsRepo.findById(tag2.getId()).orElse(null);
            assertThat(actual3).isNotNull();
        }
    }
    

    关于参数化测试,您无法使用自动递增的id提前知道id

  • 相关问题