【问题标题】:Parameterized tests fail with mvn test参数化测试因 mvn test 失败
【发布时间】:2019-11-27 15:41:34
【问题描述】:

我在一个简单的参数化 java 测试中苦苦挣扎,但找不到合适的解决方案:-S

也许你可以提示我错过了什么。

以下我一直在测试的场景 运行

  • intellij -> 没有错误,所有测试通过
  • mvn clean -Dtest:KnockoutTests test -> 没有错误,所有测试通过
  • mvn clean test(本地和詹金斯)-> ArrayIndexOutOfBoundsException

当我在我的班级RoundDefinition 中复制准确生成的hashCode 方法时,它工作得很好。但我不想明确地用生成的方法覆盖hashCode 方法......(这显然不是解决方案)

型号

@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<>();

[...]

}

测试

@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;
    }
[...]
}

控制台输出

############# [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)

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;
    }

#2 编辑:

切换到显式生成

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
        }

#3 编辑:

出于好奇,我尝试将一个元素添加到一组不同的类中

Set<Tournament> tournamentSet = new HashSet<>();
tournamentSet.add(new Tournament()); <-- ArrayIndexOutOfBoundsException

还将此类初始化添加到其他测试中...相同的行为o.O 但是我可以将字符串添加到HashSet&lt;String&gt;...这里发生了什么:-D

#4 编辑:

检查依赖关系是否有变化,但它们似乎与源分支相同。也可以在源分支中重现...

#5 编辑:

从我的模型“RoundDefinition”中删除了 lombok 注释“@Data”,自己编写了 getter 和 setter,测试再次正常工作...... 使用 lombok v1.18.8

那么为什么lombok生成hashCode和equals函数会失败....

【问题讨论】:

  • 你能看到 Lombok 为hashCode 生成的代码,了解它为什么会抛出 ArrayOutOfBoundException 吗?
  • 编辑了我的问题
  • 我认为这里还有其他情况,描述本身没有意义。我建议创建一个minimal reproducible example 并找出难题的哪个特定部分导致了问题。也许从消除参数化测试的复杂性开始 - 只需编写一个单元测试。
  • 是的,这将是我的下一次尝试。仅供参考,我刚刚将new HashSet&lt;&gt;( roundDefinitions ) 切换为显式循环。我认为我的实体类有问题
  • 使用mvn clean test 运行时没有任何特殊运行器的单次测试失败,但在mvn clean -Dtest:KnockoutTests test 或IDE 下运行时成功完成。所以完全相同的行为...... wtf

标签: java maven junit lombok parameterized


【解决方案1】:

太好了,我终于到了可以继续前进的地步了……

当我进行了几次测试时,我注意到我的测试以某种方式再次起作用了。

当我使用配置文件运行测试时它们失败了,当没有配置文件运行时它们工作。 经过一些挖掘和重构后,我得到了项目的 pom 文件......

插件“maven-sufefire-plugin”像这样被添加了2次

<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>
[...]

但是属性${argLine} 根本没有在 pom 文件中设置。 所以我引入了一个新属性&lt;argLine&gt; 并将这些参数放在那里……瞧,它起作用了…… 不知道为什么在 hashcode 方法中抛出异常,但也许这对其他人也有帮助:-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2019-07-31
    • 2016-12-09
    • 2020-03-26
    • 1970-01-01
    相关资源
    最近更新 更多