Search code examples
javaspringspring-test-mvc

How to test json api when collection is Set


I read that it is preferable to use the Set instead List in Hibernate relation.

I created two entities in relation to one to many:

@Entity
public class Product {

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

    @Column(nullable = false, unique = true)
    private String name;

    @ManyToOne
    @JoinColumn(name = "company_id", nullable = false)
    private Company company;
}

@Entity
public class Company {

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

    @Column(nullable = false, unique = true)
    private String name;

    @LazyCollection(LazyCollectionOption.TRUE)
    @OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
    private Set<Product> products;
}

In relation @OneToMany set collection private Set products;

Then I try to test the return result:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class CompanyControllerTest {

    private static final String API_COMPANY = "/api/company/";

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

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

    @Test
    public void getById() throws Exception {
        int id = 1;

        this.mockMvc.perform(get(API_COMPANY + id))
                .andExpect(status().isOk())
                .andExpect(content().contentType(APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("id", is(1)))
                .andExpect(jsonPath("$.name", is("Google")))
                .andExpect(jsonPath("$.products", hasSize(2)))
                .andExpect(jsonPath("$.products[0].id", is(1)))
                .andExpect(jsonPath("$.products[0].name", is("search engine")))
                .andExpect(jsonPath("$.products[0].company").doesNotExist())
                .andExpect(jsonPath("$.products[1].id", is(2)))
                .andExpect(jsonPath("$.products[1].name", is("adv.")))
                .andExpect(jsonPath("$.products[1].company").doesNotExist());
    }
}

But the problem is that the list of products is constantly changing, because I use a Set. And it turns out that the test either passes or fails, since the order of the products changes.

My question is how to test the result when using Set.


Solution

  • You can get all the elements with [*] and give a Matchers.containsInAnyOrder(T...) all the elements that you want to check.

    Something like this:

     this.mockMvc.perform(get(API_COMPANY + id))
                .andExpect(status().isOk())
                .andExpect(content().contentType(APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("id", is(1)))
                .andExpect(jsonPath("$.name", is("Google")))
                .andExpect(jsonPath("$.products", hasSize(2)))
                .andExpect(jsonPath("$.products[*].id", Matchers.containsInAnyOrder(1, 2)))
                .andExpect(jsonPath("$.products[*].name", Matchers.containsInAnyOrder("search engine", "adv.")))
                .andExpect(jsonPath("$.products[*].company").doesNotExist());