I try to use mock to verify method for serveral times.But I meet this problem.
org.mockito.exceptions.verification.TooLittleActualInvocations:
personDao.update(isA(com.zhaolu08.Person));
Wanted 3 times:
-> at com.zhaolu08.PersonServiceTest.testUpdate(PersonServiceTest.java:32)
But was 1 time:
while my code is:
package com.zhaolu08;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.isA;
import static org.mockito.Mockito.eq;
public class PersonServiceTest {
private PersonDao mockDao;
private PersonService personService;
#Before
public void setUp() throws Exception {
//模拟PersonDao对象
mockDao = mock(PersonDao.class);
when(mockDao.getPerson(1)).thenReturn(new Person(1, "Person1"));
when(mockDao.update(isA(Person.class))).thenReturn(true);
personService = new PersonService(mockDao);
}
#Test
public void testUpdate() throws Exception {
boolean result = personService.update(1, "new name");
Assert.assertTrue("must true", result);
verify(mockDao, times(2)).getPerson(eq(1));
verify(mockDao, times(3)).update(isA(Person.class));
}
}
I can't find out the problem. I try some methods. They did not work.
My IDE is idea.
Maven pom is:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
</dependency>
I can't find out why it doesn't work. It is just a simple demo. It's too wired.
It seems due to the fact that you are expecting personDao.update to be invoked 3 times and actually in your method personService.update(1, "new name"); it is getting invoked only 1 time
Related
Am new to springboot and am trying to integrate Integration Tests using Rest-assured to test my Rest-Api.
Am getting NPE when injecting #Steps into SpringBoot Test.I'm introducing a step class to improve on re-usability code.This test runs well if the step method is in the IT-class.I tried #Component annotation but it didn't work
Step class
import net.thucydides.core.annotations.Step;
import org.apache.http.HttpStatus;
import static com.jayway.restassured.RestAssured.when;
public class StaffSteps {
protected static String BASE_STAFF_URL = "/api/v1a/staff/";
protected static Staff staff;
#Step
public StaffSteps getStaffMemberById(String id){
staff = when().get(BASE_STAFF_URL+id)
.then().assertThat()
.statusCode(HttpStatus.SC_OK)
.extract()
.as(Staff.class);
return this;
}
#Step
public Staff getStaff(){return staff;}
}
import net.thucydides.core.annotations.Steps;
import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.List;
import static com.jayway.restassured.RestAssured.when;
#RunWith(SpringJUnit4ClassRunner.class)
public class StaffControllerIT extends BaseTest {
#Steps
private StaffSteps staffSteps;
#Before
public void setUp(){
}
#Test
public void getStaffMemberById(){
String id ="ff8081817049a34e017049a379320000";
Staff staff = staffSteps.getStaffMemberById(id).getStaff();
System.err.println(staff);
}
When i run this test, staffSteps is null.
Here is my dependency i used
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>1.9.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
Please let me know if you need more information on this. Thanks
Solution using SpringRunner:
Annotate the steps with #Bean and #StepScope, and as a result, this object will share its lifetime with StepExecution.
public class StaffStepsConfig {
protected static String BASE_STAFF_URL = "/api/v1a/staff/";
protected static Staff staff;
#Bean
#StepScope
public StaffSteps getStaffMemberById(String id){
staff = when().get(BASE_STAFF_URL+id)
.then().assertThat()
.statusCode(HttpStatus.SC_OK)
.extract()
.as(Staff.class);
return this;
}
#Bean
#StepScope
public Staff getStaff(){return staff;}
}
In the Test class, the spring-batch-test dependency provides a set of useful helper methods and listeners that can be used to configure the Spring Batch context during testing.
#RunWith(SpringRunner.class)
//#SpringBatchTest
//#SpringBootTest
#EnableAutoConfiguration
#ContextConfiguration(classes = { StaffStepsConfig.class })
#DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class StaffControllerIT extends BaseTest {
#Autowired
private StaffSteps staffSteps;
#Before
public void setUp(){
}
#Test
public void getStaffMemberById(){
String id ="ff8081817049a34e017049a379320000";
Staff staff = staffSteps.getStaffMemberById(id).getStaff();
System.err.println(staff);
}
}
Note: This runner recognizes #SpringBootTest . I think the problem is in the way the test outcomes are generated. The steps are not being read by Serenity. Spring will inject #Autowired classes, and #serenity will inject #steps classes. I assume this happens because serenity and spring are creating components in different contexts .
required dependencies in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.9.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<version>4.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
I'm trying to mock a controller/resource including the jax-rs layer. The class has dependencies that need to be injected.
It however also has some String values that are injected using a qualifier interface.
Basically, I'm using JerseyTest to run a single controller and use HK2 for dependency injection. I created a ResourceConfig and registered a AbstractBinder to bind the injected classes.
This works fine for regular injected dependencies, but when the the additional #SomeQualifierInterface annotation is added, it crashes with the following error:
MultiException stack 1 of 3
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=String,parent=ThingsController,qualifiers={#com.company.SomeQualifierInterface()},position=-1,optional=false,self=false,unqualified=null,10035302)
...
MultiException stack 2 of 3
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.company.ThingsController errors were found
...
MultiException stack 3 of 3
java.lang.IllegalStateException: Unable to perform operation: resolve on com.company.ThingsController
...
See the simplified full code example below:
Controller / Resource
import org.slf4j.Logger;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
#Path("/things")
public class ThingsController {
#Inject
private Logger log;
#Inject
#SomeQualifierInterface
private String injectedQualifierValue;
#GET
public Response getThings() {
log.info("getting things");
System.out.println("Injected value: " + injectedQualifierValue);
return Response.status(200).entity("hello world!").build();
}
}
Qualifier interface
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RUNTIME)
#Target({ TYPE, METHOD, FIELD, PARAMETER })
public #interface SomeQualifierInterface { }
Producing service
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
#ApplicationScoped
public class SomeProducerService {
#Produces
#Dependent
#SomeQualifierInterface
public String getQualifierValue() {
return "some value!";
}
}
Test
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.slf4j.Logger;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class MockedThingsControllerTest extends JerseyTest {
private Logger logMock = mock(Logger.class);
#Override
protected Application configure() {
ResourceConfig resourceConfig = new ResourceConfig(ThingsController.class);
resourceConfig.register(new AbstractBinder() {
#Override
protected void configure() {
bind(logMock).to(Logger.class);
bind("some mocked value").to(String.class); // Doesn't work
bind(new SomeProducerService()).to(SomeProducerService.class); // Doesn't work
}
});
return resourceConfig;
}
#Test
public void doSomething() {
Response response = target("/things").request().get();
assertEquals(200, response.getStatus());
verify(logMock).info("getting things");
}
}
POM
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.27.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.28</version>
<scope>test</scope>
</dependency>
Solved!
First, use the AbstractBinder from org.glassfish.hk2.utilities.binding.AbstractBinder instead of org.glassfish.jersey.internal.inject.AbstractBinder.
Second, create a class that extends AnnotationLiteral and implements the interface.
Last, bind the value to a TypeLiteral and set the qualifiedBy to the AnnotationLiteral.
Full code:
import org.glassfish.hk2.api.AnnotationLiteral;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.slf4j.Logger;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class MockedThingsControllerTest extends JerseyTest {
private Logger logMock = mock(Logger.class);
#Override
protected Application configure() {
ResourceConfig resourceConfig = new ResourceConfig(ThingsController.class);
resourceConfig.register(new AbstractBinder() {
#Override
protected void configure() {
bind(logMock).to(Logger.class);
bind("some mocked value").to(new TypeLiteral<String>() {}).qualifiedBy(new SomeQualifierLiteral());
}
});
return resourceConfig;
}
#Test
public void doSomething() {
Response response = target("/things").request().get();
assertEquals(200, response.getStatus());
verify(logMock).info("getting things");
}
static class SomeQualifierLiteral extends AnnotationLiteral<SomeQualifierInterface> implements SomeQualifierInterface {}
}
I'm trying to use Cucumber with TestFX but cant get any nodes from the application.
I've another class of TestFX that works fine and another class of Cucumber which also works fine. But I'm getting
org.loadui.testfx.exceptions.NoNodesFoundException: No nodes matched 'TextInputControl has text "Can you find this label"'.
TestFXBase :
import javafx.scene.Node;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.stage.Stage;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.testfx.api.FxToolkit;
import org.testfx.framework.junit.ApplicationTest;
import java.util.concurrent.TimeoutException;
public class TestFXBase extends ApplicationTest {
private static boolean isHeadless = false;
#BeforeClass
public static void setupHeadlessMode() {
if(isHeadless){
System.setProperty("testfx.robot", "glass");
System.setProperty("testfx.headless", "true");
System.setProperty("prism.order", "sw");
System.setProperty("prism.text", "t2k");
System.setProperty("java.awt.headless", "true");
}
}
#Before
public void setUpClass() throws Exception {
ApplicationTest.launch(Main.class);
}
#Override
public void start(Stage stage) throws Exception {
stage.show();
}
#After
public void afterEachTest() throws TimeoutException {
FxToolkit.hideStage();
release(new KeyCode[]{});
release(new MouseButton[]{});
}
/* Helper method to retrieve Java FX GUI Components */
public <T extends Node> T find (final String query){
return (T) lookup(query).queryAll().iterator().next();
}
}
This is my testfx base class and my cucumber runner and stepdefs extends this.
StepDefs:
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import org.junit.Test;
public class MyStepdefs extends TestFXBase {
#Test
#Given("^That \"([^\"]*)\" Exists$")
public void thatExists(String arg0) throws Throwable {
rightClickOn("#rect");
}
#Test
#Then("^Which is \"([^\"]*)\"$")
public void whichIs(String arg0) throws Throwable {
System.out.println(arg0);
}
}
Runner:
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(plugin = { "pretty" })
public class MyRunner extends TestFXBase{}
Feature:
Feature: Do label texts exist?
Scenario: Can you find this label text
Given That "Can you find this label" Exists
Then Which is "great"
So, the parameter is passed but TestFX dont start application in my cucumber runner, just tries to find nodes. There is a class that extends TestFXBase and works perfectly. How can I solve this issue?
Edit: My dependencies are
<dependency>
<groupId>org.loadui</groupId>
<artifactId>testFx</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.jfxtras</groupId>
<artifactId>openjfx-monocle</artifactId>
<version>1.8.0_20</version>
</dependency>
<dependency>
<groupId>org.testfx</groupId>
<artifactId>testfx-core</artifactId>
<version>4.0.6-alpha</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.testfx</groupId>
<artifactId>testfx-junit</artifactId>
<version>4.0.6-alpha</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
Solution here is to move content of setupHeadlessMode and setUpClass methods to TestFXBase class initializer:
static {
if (isHeadless) {
System.setProperty("testfx.robot", "glass");
System.setProperty("testfx.headless", "true");
System.setProperty("prism.order", "sw");
System.setProperty("prism.text", "t2k");
System.setProperty("java.awt.headless", "true");
}
try {
ApplicationTest.launch(Main.class);
} catch (Exception e) {
// oh no
}
}
i am already desperate, i cannot find out why this test is not evaluated as successful. I have checked it milion times:
package someptest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import java.sql.SQLException;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import somep.Order;
import somepBO.BOException;
import somepdao.OrderDAO;
public class XXX {
#Mock
OrderDAO dao;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void captor_A() throws SQLException, BOException {
Order order = new Order();
ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
when(dao.read(any(Integer.class))).thenReturn(order);
dao.read(123);
dao.read(456);
verify(dao, times(2)).read(intCaptor.capture());
#SuppressWarnings("unused")
List<Integer> xs = intCaptor.getAllValues();
assertThat(intCaptor.getAllValues(), hasItems(456));
}
}
Here is a screen from my debugging, captor catches correct values, but assertThat does not accept it, why?
Phew, something seems to go quite wrong on your machine. Based on your test, I created the following self-contained test class:
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
public class ArgumentCaptorTest {
private static class Order {
}
public static class OrderDAO {
public Order read(Integer any) {
return null;
}
}
#Mock
OrderDAO dao;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void captor_A() {
Order order = new Order();
ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
when(dao.read(any(Integer.class))).thenReturn(order);
dao.read(123);
dao.read(456);
verify(dao, times(2)).read(intCaptor.capture());
assertThat(intCaptor.getAllValues(), hasItems(456));
}
}
Used dependencies (pom.xml):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>testing</groupId>
<artifactId>testing</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.18.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
When I start the test, it runs perfectly and gives me a green bar. For what I see, you're doing it right. Maybe you have version conflicts between JUnit, Hamcrest and Mockito that lead to your error? I used these JAR versions:
junit:junit:4.12
org.hamcrest:hamcrest-core:1.3
org.mockito:mockito-core:2.18.3
I also left the imports so you can compare them with yours (just in case that a "wrong" import causes the error). As you statically import Matchers.* from the Hamcrest package, I am quite sure that this and/or your used library versions cause your problem.
I am newbie to junit Mockito framework, I have mocked the Dependency Injection using powermock framework, but I am getting error in eclipse on #Test annotation the error is "Type mismatch: cannot convert from Test to Annotation"
package org.singh.util.MockitoDemo;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.doNothing;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import org.junit.*;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ExampleUtil.class, ExamplePojo.class})
public class ExamplePojoTest{
#Test
public void testMethodMakingPrivateMethodCall() throws Exception {
ExamplePojo spyExamplePojo = PowerMockito.spy(new ExamplePojo());
when(spyExamplePojo, method(ExamplePojo.class, "privateMethod", String.class)).withArguments(anyString()).thenReturn("test test");
String result = spyExamplePojo.methodMakingPrivateMethodCall("test");
Assert.assertEquals("test test", result);
}
}
maven dependencies are
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>
When you see this error , it means you have a class name as “Test” in the same package.
Just rename that class name and it will work fine!!!!