This is the 20th day of my participation in the Genwen Challenge

Antecedents prompt

In the last article, we learned how to test for Drools rule constraints. Today we’ll learn about rule testing with ConstraintStream. Without further ado, let’s begin our study.

content

ConstraintStream includes the Constraint Verifier unit test harness. To use it, first add an optaplanner-test.jar.

Test a single constraint

Let’s take Queen N for example:

    protected Constraint horizontalConflict(ConstraintFactory factory) {
        return factory
                .fromUniquePair(Queen.class, equal(Queen::getRowIndex))
                .penalize("Horizontal conflict", SimpleScore.ONE);
    }
Copy the code

The following example uses ConstraintVerifier API to create a simple unit test for the previous constraint flow:

    private ConstraintVerifier<NQueensConstraintProvider, NQueens> constraintVerifier
            = ConstraintVerifier.build(new NQueensConstraintProvider(), NQueens.class, Queen.class);

    @Test
    public void horizontalConflictWithTwoQueens(a) {
        Row row1 = new Row(0);
        Column column1 = new Column(0);
        Column column2 = new Column(1);
        Queen queen1 = new Queen(0, row1, column1);
        Queen queen2 = new Queen(1, row1, column2);
        constraintVerifier.verifyThat(NQueensConstraintProvider::horizontalConflict)
                .given(queen1, queen2)
                .penalizesBy(1);
    }
Copy the code

This test ensures that when there are two queens in the same row, the horizontalConflict constraint assigns a penalty of 1. The following line to create a Shared ConstraintVerifier instance, using NQueensConstraintProvider initialization of the instance.

    private ConstraintVerifier<NQueensConstraintProvider, NQueens> constraintVerifier
            = ConstraintVerifier.build(new NQueensConstraintProvider(), NQueens.class, Queen.class);
Copy the code

The @test annotation indicates that the method is a unit Test in the testing framework of your choice. Constraint Verifier works with a number of testing frameworks, including JUnit and AssertJ.

The first part of testing is preparing test data. In this case, the test data includes two instances of the Queen plan entity and their dependencies (Row, column).

        Row row1 = new Row(0);
        Column column1 = new Column(0);
        Column column2 = new Column(1);
        Queen queen1 = new Queen(0, row1, column1);
        Queen queen2 = new Queen(1, row1, column2);
Copy the code

Looking further down, the following code tests the constraint:

    constraintVerifier.verifyThat(NQueensConstraintProvider::horizontalConflict)
            .given(queen1, queen2)
            .penalizesBy(1);
Copy the code

VerifyThat () call is used to specify the tested NQueensConstraintProvider such a method. This method must be visible to the test class, and the Java compiler will enforce it.

The given() call is used to enumerate all the facts that the constraint flow will operate on. In this case, the Given () call takes the queen1 and Queen2 instances that you created earlier. Alternatively, you can use the givenSolution() method here to provide a planned solution.

Finally, the policizesBy() call completes the test, ensuring that the level conflict constraint, given a Queen, results in a penalty of 1. This number is the match weight defined in the constraint flow multiplied by the score of the number of matches.

Alternatively, you can use the rewardsWith() call to check for rewards instead of penalties. The approach used here depends on whether the relevant constraint flow terminates with a penalty or a reward building block.

Test all constraints

In addition to testing a single constraint, you can test an entire ConstraintProvider instance. Consider the following test:

    @Test
    public void givenFactsMultipleConstraints(a) {
        Queen queen1 = new Queen(0, row1, column1);
        Queen queen2 = new Queen(1, row2, column2);
        Queen queen3 = new Queen(2, row3, column3);
        constraintVerifier.verifyThat()
                .given(queen1, queen2, queen3)
                .scores(SimpleScore.of(-3));
    }
Copy the code

There are only two obvious differences from the previous example.

First, the verifyThat() call here requires no arguments, indicating that the entire ConstraintProvider instance is being tested.

Second, the scores() method is used instead of the penalizesBy() or rewardsWith() calls. This method runs ConstraintProvider on the given fact and returns the sum of **” scores “** of all constraint matches produced by the given fact.

Using this approach, you ensure that the constraint provider doesn’t miss any constraints, and that the scoring function remains consistent as your code base evolves.

The results view

Mismatch result:


java.lang.AssertionError: Broken expectation.
        Constraint: org.optaplanner.examples.nqueens.domain/Horizontal conflict
  Expected penalty: 1 (class java.lang.Integer)
    Actual penalty: 0 (class java.lang.Integer)

  Explanation of score(0) :Constraint match totals:
        0: constraint (Horizontal conflict) has 0 matches:
    Indictments:


	at org.optaplanner.test.impl.score.stream.DefaultSingleConstraintAssertion.assertImpact(DefaultSingleConstraintAssertion.java: 112).at org.optaplanner.test.impl.score.stream.DefaultSingleConstraintAssertion.penalizesBy(DefaultSingleConstraintAssertion.java60) :at org.optaplanner.t
Copy the code

The normal result is the same as in the previous chapter.

conclusion

Through this example, we learned how OptaPlanner tests ConstraintStream’s constraint rules, which is important because you don’t expect to test in production, or need a complete set of solution data locally to start testing.

conclusion

In the next chapter we’ll learn how to look at an example of constraint scoring.

Creation is not easy, unauthorized reprint is prohibited. If my article is helpful to you, please like/favorites/follow it to encourage and support 💕💕💕💕 college