Search code examples
kotlinoptaplanner

How to initialize correctly the ConstraintVerifier for testing Optaplanner ConstraintStreams in Kotlin


How can I initialize a ConstraintVerifier in Kotlin without using Drools and Quarkus? I already added the optaplanner-test JAR and the Maven Dependency for Optaplanner 8.6.0.Final and tried it the following way:

var constraintVerifier : ConstraintVerifier<GroupAssignmentConstraintProvider, GroupAssignmentSolution> =
    ConstraintVerifier.build(GroupAssignmentConstraintProvider(),
        GroupAssignmentSolution::class.java,
        GroupAssignment::class.java) 

(ConstraintProvider: GroupAssignmentConstraintProvider, Solution: GroupAssignmentSolution, PlanningEntity: GroupAssignment) The Solution class gets a mutableSetOf Students, Lecturers and some configurations (min./max. number of participants/students for a group, optimal groupsize and weighted keywords) for solving.

The result for my test

    @Test
    fun lessThanMinGroupSize() {
    val students = Student().generateStudents(2)
    val configuration = Configuration(3, 9, 5, specialKeywords)

    val lecturer = mutableSetOf(
    Lecturer("4664807", mutableListOf(KeyWord("kotlin"), KeyWord("logistics"), KeyWord("java"), KeyWord("bigdata"), KeyWord("c")), mutableListOf("BIN", "BWI", "BEC"),
        mutableListOf(LocalDate.parse("2021-08-05"), LocalDate.parse("2021-08-08")),
        false, true))

    constraintVerifier.verifyThat(GroupAssignmentConstraintProvider::minGroupSize)
        .given(students, lecturer, configuration)
        .penalizes()
}

using the minGroupSize-Constraint:

    fun minGroupSize(constraintFactory: ConstraintFactory): Constraint {
    return constraintFactory
        .from(GroupAssignment::class.java)
        .groupBy(GroupAssignment::group, count())
        .filter { group, number ->
            number < group!!.minsize
        }
        .penalize("group min Conflict", ofHard(medium))
}

tells me: (GroupAssignmentTest.kt:65 refers to the .penalizes() in the Test)

java.lang.AssertionError: Broken expectation.

Constraint: groupAssignment.solver/group min Conflict

Explanation of score (0hard/0soft):

Constraint match totals:

Indictments:

Expected penalty but there was none.

at org.optaplanner.test.impl.score.stream.DefaultSingleConstraintAssertion.assertMatch(DefaultSingleConstraintAssertion.java:185) at org.optaplanner.test.impl.score.stream.DefaultSingleConstraintAssertion.penalizes(DefaultSingleConstraintAssertion.java:82) at org.optaplanner.test.api.score.stream.SingleConstraintAssertion.penalizes(SingleConstraintAssertion.java:121) at GroupAssignmentTest.lessThanMinGroupSize(GroupAssignmentTest.kt:65) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:205) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:201) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)

Apart from that, the constraints work.

I guess, I'm not initializing or using the ConstraintVerifier the right way. Is there anyone who can help me to solve the problem? Thank you!


Solution

  • There are several issues with your test. First of all:

            .given(students, lecturer, configuration)
    

    the given() call expects individual instances. You are giving it collections of instances, specifically a mutable set of students. Your constraint does not do from(Set.class) or anything of the like, and therefore it will not see these instances. You'll have to either enumerate your students, or don't give them at all, since your constraint does neither from() nor join() on a student class.

    Furthermore, your constraint does from(GroupAssignment.class), yet I see no GroupAssignments among your given() arguments. Once again, the constraint stream has nothing to start from, and therefore the assertion message is correct - there was nothing to penalize.