'@MockK or mockk()

When using the Mockk for Android Unit tests, there is any difference of using the notation when declaring dependencies?

class Test {
    private val x: X = mockk()

    private val test = TestClass(x)
...
}

or

class Test {
    @MockK
    private lateinit var x: X

    @InjectMockKs
    private lateinit var test: TestClass
    
    @Before
    fun setup() {
        MockKAnnotations.init(this)
    }
...
}


Solution 1:[1]

I'd recommend using mockk() and "naive" constructor dependencies injection in tests rather than annotations because of these two reasons:

  1. The mockk() builder allows you to define immutable variables with val which is more safe, efficient & better* (in terms of software development at all), whereas with @Mockk you should use var keyword;

  2. @InjectMockKs is not that cool as it seems. I worked on a project where I caught the same issue that Mockito has. My teammate removed one of the class dependencies somewhere in a middle of the constuctor arguments, built & ran the code, but forgot to fix & run tests locally. He pushed those changes, but then we got an error in our "Run Tests" pipeline stage which was pointed to nowhere, just NPE about missing class. We spent some extra time to finally find the issue, the thing is

Mockito will try to inject mocks only either by constructor injection, property injection or setter injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.

https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/InjectMocks.html

Solution 2:[2]

If your TestClass's dependency gonna change, using Annotation is better.

Because you just need to add/delete one more @MockK, don't need to care about the target class's constructor.

Original

@ExtendWith(MockKExtension::class)
class Test {
    @MockK
    private lateinit var x: X

    @InjectMockKs
    private lateinit var test: TestClass
}

Add one dependency for TestClass

@ExtendWith(MockKExtension::class)
class Test {
    @MockK
    private lateinit var x: X

    @MockK
    private lateinit var y: Y  // <1> Just add this

    @InjectMockKs
    private lateinit var test: TestClass  // <2> Don't need to add the changed dependency into it's constructor
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 insotriplesix
Solution 2 Edward Lin