java - 当 Id 由数据库设置时,使用 Mockito 测试服务
问题描述
我的服务休息服务中有一个函数 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);
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
}
Kid 也有类似的实体。
如您所见,id 是由数据库设置的。实体中没有 id 设置器。构造函数也没有 id。
现在我想测试我的服务。我模拟了我的存储库并想验证我的 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 模拟的,因此该值始终为空。即使我将我的 expectedObjectDto 设置为 null 作为 id,我也需要服务中“doStuffWithKidId()”中的 id。Atm 我得到一个 NullPointerException。
是否可以像 ReflectionTestUtils.setField() 那样设置 id?在我读到的文献中,应该始终使用模拟来测试服务。这是正确的还是我需要像 H2 这样的内存数据库?
谢谢您的帮助。
解决方案
使用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);
这会将to的 和s的 ID 设置id
为等。Mother
expectedId
Kid
expectedId + 1
expectedId + 2
推荐阅读
- c# - 将 SQL 日期时间与 C# DateTime.Now 进行比较
- ruby-on-rails - 使用 Active Record 的 Graphql-Ruby 映射
- asp.net - 在 asp.net 上加载 ReactJS 视图问题与图像路径
- reactjs - 热重载无法与 React-Redux 和 Hooks 一起正常工作
- html - 如何使网格居中并将上方的行与其左侧对齐?
- javascript - 在离线桌面应用程序上显示 ZIP 存档中的图像的最有效方法是什么?
- php - 如何忽略laravel中的所有相关数据
- k6 - 在默认功能中禁用某些调用
- python - 无法获取包含请求的 url
- angular - 如何在 Angular 中包含本地库?