Java 当数据库设置Id时,使用Mockito测试服务
我的服务rest服务中有一个函数createObject():Java 当数据库设置Id时,使用Mockito测试服务,java,spring-boot,testing,junit,mockito,Java,Spring Boot,Testing,Junit,Mockito,我的服务rest服务中有一个函数createObject(): @Service public class MyService { //Repos and contructor @Transactional public ObjectDto createObject(Object) { Mother mother = new Mother(name, age); Kid kid = new Kid(name, age); mo
@Service
public class MyService {
//Repos and contructor
@Transactional
public ObjectDto createObject(Object) {
Mother mother = new Mother(name, age);
Kid kid = new Kid(name, age);
mother.addKid(kid);
this.motherRepo.saveAndFlush(mother);
Long kidId = kid.getId();
doStuffWithKidId();
return new ObjectDto()
.withMother(mother)
.withKid(kid)
.build();
}
}
我的母亲/孩子实体基本上是这样的:
@Entity
@Table("mother")
public class mother() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id)
private Long id;
//other attributes, including @OneToMany for Kid
//Getter/Setter
}
儿童也有类似的实体
如您所见,id是由数据库设置的。实体中没有id的setter。构造函数也没有id
现在我想测试我的服务。我模拟我的repo,并想验证我的ObjectDto是否包含这些值,比如id
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public MyServiceTest {
@Mock
private MotherRepo motherRepo;
@InjectMocks
private MyService myService;
@Test
void createObjectTest() {
ObjectDto expectedObjectDto = setup...;
Object inputObject = setup...;
assertThat.(this.myService.createObject(inputObject))
.isEqualToComparingFieldByField(expectedObjectDto);
}
}
预期的ObjectDto看起来像
{
"motherId":1,
"motherAge":40,
"kidId":1
...
}
问题是,id是由数据库设置的。因为没有数据库,并且存储库是用Mockito模拟的,所以该值始终为null。即使我将expectedObjectDto设置为null作为id,我也需要服务中“doStuffWithKidId()”中的id。我得到一个空点异常
是否可以像ReflectionTestUtils.setField()那样设置id?在我读过的文献中,服务应该始终使用mock进行测试。这是正确的还是我需要像H2这样的内存中的db
谢谢你的帮助。使用
doAnswer
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@RunWith(MockitoJUnitRunner.class)
public class MockitoSettingDatabaseIds {
private static class TestEntity {
private long id;
private String text;
public TestEntity(String text) {
this.text = text;
}
public long getId() {
return id;
}
public String getText() {
return text;
}
}
private interface TestEntityDAO {
void save(TestEntity entity);
}
private static long someLogicToTest(TestEntityDAO dao, TestEntity entity) {
dao.save(entity);
return entity.getId();
}
@Test
public void shouldReturnDatabaseGeneratedId() {
long expectedId = 12345L;
TestEntityDAO dao = mock(TestEntityDAO.class);
TestEntity entity = new TestEntity("[MESSAGE]");
doAnswer(invocation -> {
ReflectionTestUtils.setField((TestEntity) invocation.getArgument(0), "id", expectedId);
return null;
}).when(dao).save(entity);
assertThat(someLogicToTest(dao, entity)).isEqualTo(expectedId);
}
}
要回答您的评论,只需对Kid
集合执行相同的操作,例如
doAnswer(invocation -> {
Mother toSave = (Mother) invocation.getArgument(0);
ReflectionTestUtils.setField(toSave, "id", expectedId);
for (int k = 0; k < toSave.getKids().size(); k++) {
ReflectionTestUtils.setField(toSave.getKids().get(k), "id", expectedId + k + 1);
}
return null;
}).when(dao).save(entity);
doAnswer(调用->{
Mother-toSave=(Mother)invocation.getArgument(0);
ReflectionTestUtils.setField(保存“id”,预期id);
for(int k=0;k
这会将
母亲的id
设置为expectedId
,将孩子的id设置为expectedId+1
,expectedId+2
等。使用doAnswer
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@RunWith(MockitoJUnitRunner.class)
public class MockitoSettingDatabaseIds {
private static class TestEntity {
private long id;
private String text;
public TestEntity(String text) {
this.text = text;
}
public long getId() {
return id;
}
public String getText() {
return text;
}
}
private interface TestEntityDAO {
void save(TestEntity entity);
}
private static long someLogicToTest(TestEntityDAO dao, TestEntity entity) {
dao.save(entity);
return entity.getId();
}
@Test
public void shouldReturnDatabaseGeneratedId() {
long expectedId = 12345L;
TestEntityDAO dao = mock(TestEntityDAO.class);
TestEntity entity = new TestEntity("[MESSAGE]");
doAnswer(invocation -> {
ReflectionTestUtils.setField((TestEntity) invocation.getArgument(0), "id", expectedId);
return null;
}).when(dao).save(entity);
assertThat(someLogicToTest(dao, entity)).isEqualTo(expectedId);
}
}
要回答您的评论,只需对Kid
集合执行相同的操作,例如
doAnswer(invocation -> {
Mother toSave = (Mother) invocation.getArgument(0);
ReflectionTestUtils.setField(toSave, "id", expectedId);
for (int k = 0; k < toSave.getKids().size(); k++) {
ReflectionTestUtils.setField(toSave.getKids().get(k), "id", expectedId + k + 1);
}
return null;
}).when(dao).save(entity);
doAnswer(调用->{
Mother-toSave=(Mother)invocation.getArgument(0);
ReflectionTestUtils.setField(保存“id”,预期id);
for(int k=0;k
这会将母亲的id
设置为expectedId
,Kid
s的id设置为expectedId+1
,expectedId+2
等。有效,谢谢。我只是想将它调整为doAnswer(…).when(doa).save(any()),因为我无法将它放入someLogicToTest()。它适用于母实体。但是我不能使用kid实体的解决方案,因为我没有使用它的doa.save()或类似的东西。有什么建议吗?谢谢,伙计,很有效!如果可以的话,我会多次投票:)非常感谢,我已经为此奋斗了两天。这很有效,谢谢。我只是想将它调整为doAnswer(…).when(doa).save(any()),因为我无法将它放入someLogicToTest()。它适用于母实体。但是我不能使用kid实体的解决方案,因为我没有使用它的doa.save()或类似的东西。有什么建议吗?谢谢,伙计,很有效!如果可以的话,我会多次投票:)非常感谢,我已经为此挣扎了两天了。