2015-11-24 65 views
2

我有Spring Boot项目,测试不失败(但应该)。春季开机测试:测试通过,但不应该(假阳性)

我做错了什么或它是一个问题与春季?

对于一个小例子,我创建了一个包含2个实体(用户和类别)和一个具有DELETE方法(https://github.com/sk8ter/demo)的控制器类的小项目。

类别实体拥有User实体的无级联选择一个ID,所以在删除具有类用户应该失败:

@Entity 
@Table(name = "user") 
public class User { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 
    ... 
} 

@Entity 
@Table(name = "category") 
public class Category { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 

    @ManyToOne 
    @JoinColumn(name = "user_id", nullable = false) 
    private User user; 
    ... 
} 

控制器也很简单:

@RestController 
@RequestMapping(value = "/users", produces = "application/json;charset=UTF-8") 
public class UserCategory { 

    @Autowired 
    private UserRepository userRepository; 

    @ResponseStatus(HttpStatus.OK) 
    @RequestMapping(value = "/{id}", method = DELETE, consumes = MediaType.ALL_VALUE) 
    public void deleteCategory(@PathVariable Long id) { 
     User user = userRepository.getOne(id); 
     userRepository.delete(user); 
    } 
} 

最后一个测试:

@Transactional 
@WebAppConfiguration 
@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = DemoApplication.class) 
public class DemoApplicationTests { 

    @Autowired 
    protected WebApplicationContext context; 

    protected MockMvc mockMvc; 

    @Before 
    public void setUp() { 
     mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); 
    } 

    @Test 
    public void testName() throws Exception { 
     mockMvc.perform(delete("https://stackoverflow.com/users/1")) 
       .andExpect(status().isOk()); 

//  EntityManagerFactory entityManagerFactory = context.getBean(EntityManagerFactory.class); 
//  SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class); 
//  sessionFactory.getCurrentSession().flush(); 
    } 
} 

如果我从DemoApplicationTests删除@Transactional注释,但在这种情况下,更改将提交给数据库。

在测试中评论3行也没有帮助。

+0

工作,你确定你有类别中,外国关键点给你的用户? –

+0

是的,我还能如何区分特定用户的类别。 –

+0

你应该有一个ManyToMany表(category_id,user_id),否则你将不得不为不同的用户重复相同的类别,但这不是线索,我问你是否确定你的db已经创建了类实体女巫被分配给某些用户?因为如果你这样做,数据库不会允许你删除没有在表上设置级联选项的用户,否则如果你只是删除了一个用户而没有分配给类别,那么测试会通过,因为你没有滥用外键规则 –

回答

2

我不想注释方法或类@Rollback(false),因为我想我所有的测试是idempotent。如果我注释@Rollback(false),H2也会因外键约束而失败。

我找到了一个解决方案:

@Transactional 
@WebAppConfiguration 
@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = DemoApplication.class) 
public class DemoApplicationTests { 

    @Autowired 
    protected WebApplicationContext context; 

    protected MockMvc mockMvc; 

    @PersistenceContext 
    EntityManager em; 

    @Before 
    public void setUp() { 
     mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); 
    } 

    @Test 
    public void testName() throws Exception { 
     mockMvc.perform(delete("https://stackoverflow.com/users/1")) 
       .andExpect(status().isOk()); 

     em.flush(); 
    } 
} 

重点线:

@PersistenceContext 
EntityManager em; 
... 
// Manual flush is required to avoid false positive in test 
em.flush(); 

所以SessionFactory并没有从Spring Documentation

// Manual flush is required to avoid false positive in test 
sessionFactory.getCurrentSession().flush(); 
+0

解决方法似乎没问题,但SessionFactory不起作用,因为您使用JPA将它包装在实体管理器中,您应该重写您的测试,因为您实际上正在检查状态是否正常,并且它在200之后使您.flush()会引起异常 –

+0

你有什么建议?你能举个例子吗? –