Why is delete working in app but not in tests?

Viewed 210

Here's my case.

Category.java

@Getter
@Entity
@NoArgsConstructor
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String name;

  @ManyToOne
  @JoinColumn(name = "masterCategory.id")
  private MasterCategory masterCategory;

  @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true)
  private List<Expense> expenses = new ArrayList<>();

}

Expense.java

@Getter
@Entity
@NoArgsConstructor
public class Expense {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private BigDecimal amount;
  private String itemName;
  private LocalDateTime expenseDate;
  private String shopName;
  private boolean isIncome;

  @ManyToOne
  @JoinColumn(name = "shop.id")
  private Shop shop;

  @ManyToOne
  @JoinColumn(name = "bankingAccount.id")
  private BankingAccount bankingAccount;

  @ManyToOne
  @JoinColumn(name="category.id")
  private Category category;

  @ManyToOne
  @JoinColumn(name = "userAccount.id")
  private UserAccount userAccount;

  @ManyToOne
  @JoinColumn(name = "userGroup.id")
  private UserGroup userGroup;

}

As we can see, they are linked though a relation. I also have simple service, repository and controller (spring boot) for each of these class. CategoryService contains method for deleting controller. Its also quite simple.

Category category = categoryRepository.selectCategory(getLoggedUsername(),groupId,masterCatId,categoryId);
categoryRepository.delete(category);
return categoryConverter.toMinimalDto(category);

And when I run the app, everything works perfectly, its removing the category from database, its removing expenses connected to that category. One day I decided to write tests cause I was tired of checking everything manually. Heres the test method:

@Test
@WithMockUser(username = LOGIN)
public void shouldDeleteCategoryAndConnectedExpenses__andReturn200() throws Exception {
    //given
    mvc.perform(get("/api/budget/1/master/1"))
            .andExpect(status().isOk())
            .andExpect(content().json(testUtil.openJson("categories/categoriesFromSelectedBudget.json")));
    mvc.perform(get("/api/budget/1/master/1/category/1/expense"))
            .andExpect(status().isOk())
            .andExpect(content().json(testUtil.openJson("expenses/expensesFromCategory1.json")));
    //when
    mvc.perform(delete("/api/budget/1/master/1/category/1"))
            .andExpect(status().isOk());
    //then
    mvc.perform(get("/api/budget/1/master/1"))
            .andExpect(status().isOk())
            .andExpect(content().json(testUtil.openJson("categories/categoriesAfterDelete.json")));
    mvc.perform(get("/api/budget/1/master/1/category/1/expense"))
            .andExpect(status().isNotFound());
}

I have a special postgresDB for tests, here I check if delete is really doing its job. I do this by checking if response jsons are the ones I want them to be. Simple stuff.

  • First get (categoriesFromSelectedBudget.json) contains 3 elements
  • Third get (categoriesAfterDelete.json) contains 2 elements.

These jsons are 100% correct.

The question is: why when application is run, everything works correctly (I can see SQLs with delete, correct rows are deleted from DB) but when tests are run the follwoing exception is thrown:

java.lang.AssertionError: []: Expected 2 values but got 3

In test, delete gives me http 200 but it's clearly not deleting the element. Also there are no SQLs with delete. Why? What did I do wrong?

1 Answers

Thanks for leads. After some debugging I realised that test behave like this because of @Transactional on top of the test class. I did it to refresh database after each method. I replaced it with @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) and everything seems to work fine.

Related