I want to inquire how to mock a repository class and make a unit test for its functions.
Repository Class
class RequestRepository {
/** suspend function to get the result of token request from API*/
suspend fun getToken(userLoginModel: UserLoginModel): Response<TokenResponse> {
return ApiService.APILogin.getToken(userLoginModel)
}
// many more functions to come here
…
}
I tried this test function but it did not work
class LoginUnitTest {
private var repositoryTest = RequestRepository()
private var userLoginModelTest = Mockito.mock(UserLoginModel::class.java)
#Test
suspend fun login_with_correct_login_and_password() {
userLoginModelTest.email = "wrong mail"
userLoginModelTest.password = "wrong password"
var resultTest: Boolean = repositoryTest.getToken(userLoginModelTest).isSuccessful
if (resultTest)
assert(resultTest) { " we have issue in this function " }
else
assert(resultTest) { " we are good " }
}
}
I recieved this error message:
org.junit.runners.model.InvalidTestClassError: Invalid test class 'fr.mastergime.moez.arkindex.LoginUnitTest':
1. Method login_with_correct_login_and_password() should be void
2. Method login_with_correct_login_and_password should have no parameters
at org.junit.runners.ParentRunner.validate(ParentRunner.java:525)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:102)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:84)
at org.junit.runners.JUnit4.<init>(JUnit4.java:23)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.requests.ClassRequest.createRunner(ClassRequest.java:28)
at org.junit.internal.requests.MemoizingRequest.getRunner(MemoizingRequest.java:19)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
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 com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:64)
I notice four things here:
You ask for mocking of the repository, but instead mock the model class that you do not show.
You use JUnit 4, which is, well, ancient. Please use JUnit 5 Jupiter. (Or some Kotlin-specific framework.)
You use Mockito, which is not bad in general. For Kotlin, however, you should consider MockK, which can mock some of the things that are particular to Kotlin (like suspend-functions).
Finally, the real reason why you setup fails: You cannot have a suspend-function as a test method in JUnit. Remove the suspend keyword for login_with_correct_login_and_password.
Related
The class under test looks like:
class State(pivate val repo){
val values = listOf<Int>()
fun update() {
values = repo.generateValues() // <-line 375
}
}
The unit test looks like:
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
private class StateTest {
#MockK(relaxed = true) private lateinit var mockedRepo: Repo
#BeforeAll
fun config() {
MockKAnnotations.init(this)
}
#BeforeEach
fun setup() {
clearAllMocks()
unmockkAll()
}
#Test
fun `invoke update`() {
val state = mockk<State>(relaxed = true)
every { state.repo } answers { mockedRepo }
every { mockedRepo.generateValues() } returns listOf(1,2,3)
every { state.update() } answers { callOriginal() }
state.update()
Assertions.assertTrue(state.values.size > 0)
}
}
Runnig the test, a NullPointerException is thrown:
java.lang.NullPointerException
at com.name.someapp.someservice.State.update(State.kt:375)
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 io.mockk.proxy.jvm.advice.MethodCall.call(MethodCall.kt:14)
at io.mockk.proxy.jvm.advice.SelfCallEliminatorCallable.call(SelfCallEliminatorCallable.kt:14)
at io.mockk.impl.instantiation.JvmMockFactoryHelper.handleOriginalCall(JvmMockFactoryHelper.kt:95)
at io.mockk.impl.instantiation.JvmMockFactoryHelper.access$handleOriginalCall(JvmMockFactoryHelper.kt:18)
at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1$invocation$$inlined$stdFunctions$lambda$1.invoke(JvmMockFactoryHelper.kt:27)
at io.mockk.impl.stub.MockKStub$handleInvocation$originalPlusToString$1.invoke(MockKStub.kt:230)
at io.mockk.MockKAnswerScope.callOriginal(API.kt:2205)
The reason you're getting the NullPointerException is that fun update() does not call getRepo() (which you've mocked) but instead it uses the backing field repo directly. (You can see this by compiling the Kotlin source to bytecode and decompiling to Java in IntelliJ IDEA.) This is also documented at kotlinlang.org:
ⓘ On the JVM: Access to private properties with default getters and setters is optimized to avoid function call overhead.
The answer is, as sidgate said in the comment, to create a real (not mock) instance of State and pass the mock repo to it constructor:
val state = State(mockRepo)
It is a code smell to mock the "system under test".
i want to make a unit testing by using mockito dependencies on my code. it is always failed because view.processMatchData(data) and view.hideLoading() are in closure part in this presenter code, so that unit test will not detect them. Please, somebody help me solve this problem.
open class MatchSearchPresenter(
private val view: MatchSearchView,
private val apiService: ApiService,
private val cari : String
) {
fun searchMatch() {
view.showLoading()
apiService.loadSearchMatch(cari).enqueue(object : Callback<MatchSearchResponseModel> {
override fun onResponse(call: Call<MatchSearchResponseModel>, response: Response<MatchSearchResponseModel>)
{
if (response.isSuccessful) {
val data = response.body()!!
view.processMatchData(data)
}
view.hideLoading()
}
override fun onFailure(call: Call<MatchSearchResponseModel>, error: Throwable)
{
Log.e("Error", error.message)
view.hideLoading()
}
})
}
}
here are my unit test :
class MatchSearchPresenterTest {
#Mock
private lateinit var view: MatchSearchView
#Mock
private lateinit var apiService: ApiService
#Mock
private lateinit var teamPresenter: MatchSearchPresenter
#Mock
private lateinit var call: Call<MatchSearchResponseModel>
#Mock
private lateinit var something: Callback<MatchSearchResponseModel>
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val kata = "Man United"
teamPresenter = MatchSearchPresenter(view, apiService, kata )
}
#Test
fun searchMatch() {
val teamId = "Man United"
val teams: MutableList<PrevMatchData> = mutableListOf()
val data = MatchSearchResponseModel(teams)
teamPresenter.searchMatch()
argumentCaptor<MatchSearchView>().apply {
Mockito.verify(apiService.loadSearchMatch(teamId).enqueue(something))
firstValue.processMatchData(data)
firstValue.hideLoading()
}
Mockito.verify(view).showLoading()
Mockito.verify(view).processMatchData(data)
Mockito.verify(view).hideLoading()
}
}
but this is not working by showing message like this :
java.lang.NullPointerException
at com.example.footballleaguecataloguefourth.ui_bottom_navigation.schedule.match_search.MatchSearchPresenter.searchMatch(MatchSearchPresenter.kt:19)
at com.example.footballleaguecataloguefourth.ui_bottom_navigation.schedule.match_search.MatchSearchPresenterTest.searchMatch(MatchSearchPresenterTest.kt:41)
I think what you want here is to have the call returned by ApiService call the correct method as soon as it's enqueued.
To do this you can use Mockito's thenAnswer - Here's an example. In your case, you can try this:
Mockito.`when`(call.enqueue(Mockito.any())).thenAnswer {
(it.getArgument(0) as Callback<MatchSearchResponseModel>).onResponse(
call,
Response.success(MatchSearchResponseModel(/*whatever is needed to build this object*/))
)
}
Here, you make sure that once call.enqueue is called with any argument, it'll immediately call the onResponse method with a success reponse. You can do something similar for an error and you can also call onFailure.
The last thing you need to do is to make sure that your api service returns the configured mocked call:
Mockito.`when`(apiService.loadSearchMatch(kata)).thenReturn(call)
I'd put this per test. So before you call your presenter method, I'd configure the mocks like this.
Now, calling teamPresenter.searchMatch(), should call apiService.loadSearchMatch(cari), which will return the mocked call that once enqueued will call the passed callback's onResponse method.
Lastly, as you might have noticed when is actually written with backticks. This is because it's a kotlin keyword that needs to be escaped. Not only for this reason but many more, you could consider using Mockito Kotlin which is a superb kotlin library wrapping mockito and makes life much easier.
I am assigned to add unit test code coverage to a 15 years old legacy project which is not using IoC and 0 unit test. I am not allowed to refactor the code since it works perfect fine on production, management does not want other teams get involved for refactoring such as QA testing, etc.
Service class has a performService method has following code
public void performService(requestMessage, responseMessage) {
UserAccount userAccount = requestMessage.getUserAccount();
GroupAccount groupAccount = requestMessage.getGroupAccount();
Type type = requestMessage.getType();
StaticServiceCall.enroll(userAccount, groupAccount, type);
response.setStatus(Status.SUCCESS);
}
This StaticServiceCall.enroll method is calling remote service. My unit test is
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticServiceCall.class)
public class EnrollmentServiceTest {
#Test
public void testPerformService() {
mockStatic(StaticServiceCall.class);
doNothing().when(StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class)));
service.performService(requestMessage, responseMessage);
assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);
}
Eclipse complains with The method when(T) in the type Stubber is not applicable for the arguments (void)
Eclipse stops complain if test code change to
mockStatic(StaticServiceCall.class);
doNothing().when(StaticServiceCall.class);
StaticServiceCall.enroll(any(UserAccount.class), any(GroupAccount.class), any(Type.class));
service.performService(requestMessage, responseMessage);
assertEquals("Enrollment should be success, but not", Status.SUCCESS, response.getStatus);
Test case failed with UnfinishedStubbingException. I am using powermock 1.6.6
There is a misconception on your end. You think that you need to say that doNothing() should do nothing.
That is not necessary! As these lines
#PrepareForTest(StaticServiceCall.class) ... and
mockStatic(StaticServiceCall.class);
are sufficient already.
You want to prevent the "real" content of that static method to run when the method is invoked during your test. And that is what mockStatic() is doing.
In other words: as soon as you use mockStatic() the complete implementation of the real class is wiped. You only need to use when/then/doReturn/doThrow in case you want to happen something else than nothing.
Meaning: just remove that whole doNothing() line!
#GhostCat - Thank you for your answer, it solved problem, my misconception is coming from this test case
#Test
public void testEnrollmentServiceSuccess() {
RequestMessage requestMessage = new RequestMessage();
requestMessage.setName("ENROLL");
ResponseMessage responseMessage = new ResponseMessage();
EnrollmentService mockService = mock(EnrollmentService.class);
mockService.performService(any(RequestMessage.class), any(ResponseMessage.class));
mockStatic(ClientManager.class);
when(ClientManager.isAuthenticated()).thenReturn(true);
ServiceImpl service = new ServiceImpl();
service.performService(requestMessage, responseMessage);
verify(mockService).performService(any(RequestMessage.class), any(ResponseMessage.class));
}
Here is the code snippet of ServiceImpl class based name of the request message calling different service class
public void performService(RequestMessage request, ResponseMessage response) {
try {
if (request == null) {
throw new InvalidRequestFormatException("null message");
}
if (!ClientManager.isAuthenticated()) {
throw new ServiceFailureException("not authenticated");
}
// main switch for known services
if ("ENROLL".equals(request.getName())) {
service = new EnrollmentService();
service.performService(request, response);
} else if ("VALIDATE".equals(request.getName())) {
...
Although the test passed,real implementation in EnrollmentService got called and exceptions thrown due to barebone RequestMessage object, then I googled out doNothing, thanks again for your clarification
I have a class that I want to write unit tests for. I'm using StructureMap (2.6.3) in the project and I have some problems with that.
For testing I use Nunit (2.6.0.12054) and RhinoMocks (3.6).
Normally i inject my dependencies in the constructor of my classes and then it's easy to substitute the dependencies with mocks in my unit tests. But there are a few cases where I can't do that, where I have no control over when the class under test is created. In these cases I use ObjectFactory.GetInstance() to get the dependencies.
public class MyClass
{
public int MyMethod(string parameter)
{
var myDependency = ObjectFactory.GetInstance<IMyDependency>();
try
{
return myDependency.CalculateValue(parameter);
}
catch (Exception ex)
{
//Suppress exception.
return 0;
}
}
}
For this class and method I want to write two tests. First I want to to test that the dependency is called and the value it calculates is returned by the class under test. Second, the dependency might throw an exception and I want to test that this exception is suppressed by the class under test and that it return zero in that case.
[TestFixture]
public class MyClassTests()
{
[Test]
public void MyMethod_DependencyReturnsValue_ReturnsValueFromDependency
{
//Arrange.
const int valueFromDependencyStub = 333;
var myDependencyStub = MockRepository.GenerateStub<IMyDependency>();
myDependencyStub.Stub(x => x.CalculateValue()).Return(valueFromDependencyStub);
ObjectFactory.Inject<IMyDependency>(myDependencyStub);
var target = new MyClass();
//Act.
var result = target.MyMethod("test");
//Assert.
Assert.AreEqual(valueFromDependencyStub, result);
}
[Test]
public void MyMethod_DependencyThrowsException_ReturnsZero
{
//Arrange.
var myDependencyStub = MockRepository.GenerateStub<IMyDependency>();
myDependencyStub.Stub(x => x.CalculateValue()).Throw(new Exception());
ObjectFactory.Inject<IMyDependency>(myDependencyStub);
var target = new MyClass();
//Act.
var result = target.MyMethod("test");
//Assert.
Assert.AreEqual(0, result);
}
}
Both these tests work if I run them individually, but if I run the both it does not work. I my real case the second test, where the stubbed dependency throws an exception, runs first. When the other test runs the stubbed dependency still throws an exception.
The problem, as I understand it, is that I'm using the global ObjectFactory and inject my stub into that. That would probably work if I could clear the ObjectFactory after each test, but I found no way to do that. ObjectFactory.EjectAllInstancesOf() sounded like something that would work, but it doesn't.
How do I solve this? Either by changing my test or by actually rewriting the class under test.
First-timer here, apologies if I've missed anything.
I'm hoping to get around a call to a static method using Spock. Feedback would be great
With groovy mocks, I thought I'd be able to get past the static call but haven't found it.
For background, I'm in the process of retrofitting tests in legacy java. Refactoring is prohibited. I'm using spock-0.7 with groovy-1.8.
The call to the static method is chained with an instance call in this form:
public class ClassUnderTest{
public void methodUnderTest(Parameter param){
//everything else commented out
Thing someThing = ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(param);
}
}
staticMethod returns an instance of ClassWithStatic
instanceMethod returns the Thing needed in the rest of the method
If I directly exercise the global mock, it returns the mocked instance ok:
def exerciseTheStaticMock(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
when:
println(ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(testParam))
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
But if I run the methodUnderTest from the ClassUnderTest:
def failingAttemptToGetPastStatic(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
ClassUnderTest myClassUnderTest = new ClassUnderTest()
when:
myClassUnderTest.methodUnderTest(testParam)
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
It throws down a real instance of ClassWithStatic that goes on to fail in its instanceMethod.
Spock can only mock static methods implemented in Groovy. For mocking static methods implemented in Java, you'll need to use a tool like GroovyMock , PowerMock or JMockit.
PS: Given that these tools pull of some deep tricks in order to achieve their goals, I'd be interested to hear if and how well they work together with tests implemented in Groovy/Spock (rather than Java/JUnit).
Here is how I solved my similar issue (mocking a static method call which is being called from another static class) with Spock (v1.0) and PowerMock (v1.6.4)
import org.junit.Rule
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification
import static org.powermock.api.mockito.PowerMockito.mockStatic
import static org.powermock.api.mockito.PowerMockito.when
#PrepareForTest([YourStaticClass.class])
#PowerMockIgnore(["javax.xml.*", "ch.qos.logback.*", "org.slf4j.*"])
class YourSpockSpec extends Specification {
#Rule
Powermocked powermocked = new Powermocked();
def "something something something something"() {
mockStatic(YourStaticClass.class)
when: 'something something'
def mocked = Mock(YourClass)
mocked.someMethod(_) >> "return me"
when(YourStaticClass.someStaticMethod(xyz)).thenReturn(mocked)
then: 'expect something'
YourStaticClass.someStaticMethod(xyz).someMethod(abc) == "return me"
}
}
The #PowerMockIgnore annotation is optional, only use it if there is some conflicts with existing libraries
A workaround would be to wrap the static method call into an instance method.
class BeingTested {
public void methodA() {
...
// was:
// OtherClass.staticMethod();
// replaced with:
wrapperMethod();
...
}
// add a wrapper method for testing purpose
void wrapperMethod() {
OtherClass.staticMethod();
}
}
Now you can use a Spy to mock out the static method.
class BeingTestedSpec extends Specification {
#Subject BeingTested object = new BeingTested()
def "test static method"() {
given: "a spy into the object"
def spyObject = Spy(object)
when: "methodA is called"
spyObject.methodA()
then: "the static method wrapper is called"
1 * spyObject.wrapperMethod() >> {}
}
}
You can also stub in canned response for the wrapper method if it's supposed to return a value. This solution uses only Spock built-in functions and works with both Java and Groovy classes without any dependencies on PowerMock or GroovyMock.
The way I've gotten around static methods in Groovy/Spock is by creating proxy classes that are substituted out in the actual code. These proxy classes simply return the static method that you need. You would just pass in the proxy classes to the constructor of the class you're testing.
Thus, when you write your tests, you'd reach out to the proxy class (that will then return the static method) and you should be able to test that way.
I have recently found 'spock.mockfree' package, it helps mocking final classes and static classes/methods.
It is quite simple as with this framework, in this case, you would need only to Spy() the class under test and #MockStatic the static method you need.
Example:
We used a static method returnA of StaticMethodClass class
public class StaticMethodClass {
public static String returnA() {
return "A";
}
}
here is the calling code
public class CallStaticMethodClass {
public String useStatic() {
return StaticMethodClass.returnA();
}
}
Now we need to test the useStatic method of CallStaticMethodClass class But spock itself does not support mock static methods, and we support
class CallStaticMethodClassTest extends Specification {
def 'call static method is mocked method'() {
given:
CallStaticMethodClass callStaticMethodClass = Spy()
println("useStatic")
expect:
callStaticMethodClass.useStatic() == 'M'
}
#MockStatic(StaticMethodClass)
public static String returnA() {
return "M";
}
}
We use the #MockStatic annotation to mark which class needs to be mocked
Directly implement the static method that requires mocking under it, the method signature remains the same, but the implementation is different.
Link to the framework:
https://github.com/sayweee/spock-mockfree/blob/498e09dc95f841c4061fa8224fcaccfc53904c67/README.md