4

I have a project in Kotlin.

I created a @ConfigurationProperties class and I would like to know the best practices for unit tests.

The following is my properties class:

@ConstructorBinding
@ConfigurationProperties(prefix = "myapp")
data class MyAppProperties(
    /**
     * Base path to be used by myapp. Default is '/search'.
     */
    val basePath: String = "/myapp"
)

I inject MyAppProperties in my Controller:

@RestController
final class MyAppController(
    myAppProperties: MyAppProperties
) {

    ...

}

I want to test my Controller:

@ExtendWith(MockitoExtension::class)
internal class MyAppControllerTest {

    @Mock
    lateinit var myAppProperties: MyAppProperties

    @InjectMocks
    lateinit var myAppController: MyAppController

    ...

}

But I have the following Mockito error:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.myapp.MyAppProperties
Mockito cannot mock/spy because :
 - final class

What is the best solution to fix this problem:

    /src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: mock-maker-inline

This solution seems good since we don't modify the existing code but it adds a behavior to Mockito for the whole project and all final classes.

  • Make my properties class open
    open class MyAppProperties...

This solution requires modifying the code and makes the class extensible, which may not be a good thing?

  • Make all @ConfigurationProperties classes open via the Maven configuration:
    <plugin>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-maven-plugin</artifactId>
        <configuration>
            <args>
                <arg>-Xjsr305=strict</arg>
                <arg>-Xjvm-default=enable</arg>
            </args>
            <compilerPlugins>
                <plugin>all-open</plugin>
            </compilerPlugins>
            <pluginOptions>
                <option>all-open:annotation=org.springframework.boot.context.properties.ConfigurationProperties</option>
            </pluginOptions>
        </configuration>
        ...
    </plugin>

This solution does not require modifying the code but make all @ConfigurationProperties classes open, which may not be a good thing?

  • Do not mock the properties class and initialize it in MyAppControllerTest:
    @ExtendWith(MockitoExtension::class)
    internal class MyAppControllerTest {
    
        val myAppProperties: MyAppProperties = MyAppProperties("/mypath")
    
        ...
    }

This does not allow us to give a specific behaviour according to the test.

0 Answers0