I'm struggeling quite a bit with a simple parameterized java test and couldn't find a proper solution :-S
Maybe you can give a hint where i missed something.
Following scenarios I have been testing running with
mvn clean -Dtest:KnockoutTests test
-> no error, all tests passmvn clean test
(locally and on jenkins) -> ArrayIndexOutOfBoundsExceptionWhen I'm copying the exactly generated hashCode
method in my class RoundDefinition
it works just fine. But I don't want to explicitely override the hashCode
method with exactly the generated one... (and this cannot be the solution obviously)
Models
@Entity
@Data
@Table( name = "tbl_rounddefinition" )
@JsonIgnoreProperties( value = { "hibernateLazyInitializer", "handler", }, ignoreUnknown = true )
@ToString( exclude = { "tournament" } )
@EqualsAndHashCode( exclude = { "tournament" } )
public class RoundDefinition implements Serializable {
@Id
@GeneratedValue( strategy = IDENTITY )
@Column( name = "rounddefinition_id" )
private Long id;
@ManyToOne( fetch = FetchType.LAZY )
@JoinColumn( name = "rounddefinition_linktournamentid" )
@JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id" )
@JsonIdentityReference( alwaysAsId = true )
private Tournament tournament;
@Column( name = "rounddefinition_round" )
private Integer round;
@Column( name = "rounddefinition_numberOfRoundresults" )
private Integer numberOfRoundresults;
}
@Data
@ToString( exclude = { [...] } )
@EqualsAndHashCode( exclude = { [...], "roundDefinitions" } )
@Entity
@Table( name = "tbl_tournament" )
@JsonIgnoreProperties( value = { "hibernateLazyInitializer", "handler" }, ignoreUnknown = true )
public class Tournament implements Serializable {
[...]
@OneToMany( fetch = FetchType.LAZY, mappedBy = "tournament", cascade = CascadeType.ALL, orphanRemoval = true )
@JsonSerialize( using = CollectionSerializer.class )
@JsonDeserialize( using = CollectionDeserializer.class )
@OrderBy( " round ASC " )
private Set<RoundDefinition> roundDefinitions = new HashSet<>();
[...]
}
Test
@RunWith( Parameterized.class )
@Slf4j
public class KnockoutTests {
@InjectMocks
private Knockout underTest;
@Mock
private MatchRepository matchRepository;
private Integer tournamentSize;
private Integer expectedMatchSize;
private Integer expectedMaxRound;
private List<RoundDefinition> roundDefinitions;
public KnockoutTests( Integer tournamentSize, Integer expectedMatchSize, Integer expectedMaxRound,
List<RoundDefinition> roundDefinitions )
{
this.tournamentSize = tournamentSize;
this.expectedMatchSize = expectedMatchSize;
this.expectedMaxRound = expectedMaxRound;
this.roundDefinitions = roundDefinitions;
}
@Before
public void setUp() {
MockitoAnnotations.initMocks( this );
}
@Test
public void testGenerate() {
Tournament tournament = new Tournament();
tournament.setTeamsize( 1 );
System.out.println( "############# " + roundDefinitions.toString() + " #############" );
tournament.setRoundDefinitions( new HashSet<>( roundDefinitions ) ); // <<-- Here I'm getting this weird ArrayIndexOutOfBoundsExceptions
[...]
}
@Parameterized.Parameters( name = "{index}: Test with tournamentSize={0}, expectedMatchSize: {1}, expectedMaxRound: {2}" )
public static Collection testData() {
return Arrays.asList( new Object[][] {
{ 1, 1, 1, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 2, 1, 1, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 15, 15, 4, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
add( getRoundDefinition( 2L, 3, 3 ) );
add( getRoundDefinition( 3L, 4, 5 ) );
}} },
{ 16, 15, 4, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 17, 31, 5, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 129, 255, 8, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 256, 255, 8, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
}} },
{ 257, 511, 9, new ArrayList<RoundDefinition>() {{
add( getRoundDefinition( 1L, 1, 1 ) );
add( getRoundDefinition( 2L, 3, 3 ) );
add( getRoundDefinition( 3L, 4, 5 ) );
}} }
} );
}
private static RoundDefinition getRoundDefinition( long id, int round, int numberOfRoundresults ) {
RoundDefinition rd = new RoundDefinition();
rd.setId( id );
rd.setRound( round );
rd.setNumberOfRoundresults( numberOfRoundresults );
return rd;
}
[...]
}
Console output
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1), RoundDefinition(id=2, tournament=null, round=3, numberOfRoundresults=3), RoundDefinition(id=3, tournament=null, round=4, numberOfRoundresults=5)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1)] #############
############# [RoundDefinition(id=1, tournament=null, round=1, numberOfRoundresults=1), RoundDefinition(id=2, tournament=null, round=3, numberOfRoundresults=3), RoundDefinition(id=3, tournament=null, round=4, numberOfRoundresults=5)] #############
Tests run: 8, Failures: 0, Errors: 8, Skipped: 0, Time elapsed: 0.015 sec <<< FAILURE! - in pkg.service.tournament.handler.generator.KnockoutTests
testGenerate[0: Test with tournamentSize=1, expectedMatchSize: 1, expectedMaxRound: 1](pkg.service.tournament.handler.generator.KnockoutTests) Time elapsed: 0.008 sec <<< ERROR!
java.lang.ArrayIndexOutOfBoundsException: 35
at pkg.model.entities.RoundDefinition.hashCode(RoundDefinition.java:26)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at java.util.HashSet.<init>(HashSet.java:120)
at pkg.service.tournament.handler.generator.KnockoutTests.testGenerate(KnockoutTests.java:67)
testGenerate[1: Test with tournamentSize=2, expectedMatchSize: 1, expectedMaxRound: 1](pkg.service.tournament.handler.generator.KnockoutTests) Time elapsed: 0 sec <<< ERROR!
java.lang.ArrayIndexOutOfBoundsException: 35
at pkg.model.entities.RoundDefinition.hashCode(RoundDefinition.java:26)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at java.util.HashSet.<init>(HashSet.java:120)
at pkg.service.tournament.handler.generator.KnockoutTests.testGenerate(KnockoutTests.java:67)
Generated code by lombok
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $round = this.getRound();
result = result * 59 + ($round == null ? 43 : $round.hashCode());
Object $numberOfRoundresults = this.getNumberOfRoundresults();
result = result * 59 + ($numberOfRoundresults == null ? 43 : $numberOfRoundresults.hashCode());
return result;
}
switched to an explicit generation
Set<RoundDefinition> definitions = new HashSet<>( );
for (RoundDefinition rd : roundDefinitions) {
RoundDefinition asd = new RoundDefinition();
asd.setRound( rd.getRound() );
asd.setNumberOfRoundresults( rd.getNumberOfRoundresults() );
definitions.add(asd); // <-- ArrayIndexOutOfBoundsException
}
Out of curiosity i tried to add an element to a different set of class
Set<Tournament> tournamentSet = new HashSet<>();
tournamentSet.add(new Tournament()); <-- ArrayIndexOutOfBoundsException
Also add such initialisation to an other test... same behaviour o.O
BUT i can add string to a HashSet<String>
... the heck is going on here :-D
checked dependencies for change but they seem to be same with source branch. Also reproducable in source branch...
Removed the lombok annotation "@Data" from my model "RoundDefinition", wrote getter and setter myself and the tests work again just fine... using lombok v1.18.8
So why is it failing when lombok generates the hashCode and equals function....
Soooo finally I've got to a point with which I can get on...
As I tested several tries, I noticed that my tests somehow worked again.
When I run the tests with profile they failed, when run without a profile they worked. After some digging and refactoring I've got to the pom file of the project...
The plugin "maven-sufefire-plugin" was added 2 times like so
<project>
<profiles>
[...]
<profile>
<id>unit-test</id>
<plugins>
[...]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
${argLine} -Dfile.encodeing=utf-8 -Duser.timezone=UTC
</argLine>
</configuration>
</plugin>
[...]
<project>
<build>
<plugins>
[...]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
-Dfile.encodeing=utf-8 -Duser.timezone=UTC
</argLine>
</configuration>
</plugin>
[...]
but the property ${argLine}
was not set in the pom file at all.
So I introduced a new property <argLine>
and put those parameters in there.... and voilà it worked....
Don't know exactly why there is then an exception thrown in the hashcode method but maybe this helps someone else too :-)