0

Preconditions: I am deserializing a complex JSON into data class. The destination class has a bit of a complex hierarchy.

I have a list of objects List. Where ServiceFeature is the following (it's in kotlin, but does not matter):

data class ServiceFeature(
    val flagValue: String?,
    val effectiveFlagValue: String?,
    val name: String?,
    val attributes: List<Attribute?>?
)

As you can see ServiceFeature has an "attributes" property which includes another List of "Attribute". The main point is that Attributes in list might be in any order. Is there a reliable way to compare two lists of ServiceFeatures without order check from List<Attribute?>

I am trying to find a solution with assertJ.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Mike
  • 725
  • 1
  • 8
  • 11

2 Answers2

2

If order does not matter for your attributes and they are unique (i.e. may not have multiple attributes of the same type) you might change the structure into a Set<Attribute?> instead and just use the regular compare.

If you want to preserve order but compare (unique) attributes you may convert them to set when comparing, see Easiest way to convert a List to a Set in Java.

Jotunacorn
  • 496
  • 1
  • 4
  • 12
  • Thanks, Changing List to Set in data class works like a charm `val attributes: List? -> val attributes: Set?` – Mike Nov 07 '17 at 15:23
2

If order of elements doesn't matter, then you can use Set instead of List. Having said that, You can use containsExactlyInAnyOrder() method provided by AssertJ. This method expects var-args as an argument, so in order to convert list to array we can use toTypedArray along with spread operator E.g.


import org.junit.Test
import org.assertj.core.api.Assertions.*

data class ServiceFeature(
        val flagValue: String?,
        val effectiveFlagValue: String?,
        val name: String?,
        val attributes: List?
)

data class Attribute(val name: String?)

class SimpleTest {
    @Test
    fun test() {
        val list1 = listOf(ServiceFeature("flagA", "effectiveFlagA", "foo", listOf(Attribute("a"), Attribute("b"))))
        val list2 = listOf(ServiceFeature("flagA", "effectiveFlagA", "foo", listOf(Attribute("b"), Attribute("a"))))
        list1.zip(list2).forEach {
            assertThat(it.first.name).isEqualTo(it.second.name)
            assertThat(it.first.effectiveFlagValue).isEqualTo(it.second.effectiveFlagValue)
            assertThat(it.first.name).isEqualTo(it.second.name)
            val toTypedArray = it.second.attributes!!.toTypedArray() // null-check as per your need
            assertThat(it.first.attributes).containsExactlyInAnyOrder(*toTypedArray)
        }

    }
}
sol4me
  • 15,233
  • 5
  • 34
  • 34
  • Thanks, I tried this method. It works with Arrays, but in my case I have an Array of Objects which have one more array as property. In my case assertion fails on checking List for ServiceFeature – Mike Nov 07 '17 at 15:13
  • You can tweak the method to compare the lists, see updated answer – sol4me Nov 07 '17 at 15:28