ArgumentCaptor 在单元测试中的使用
ArgumentCaptor usage in Unit Tests
我正在尝试为以下服务方法创建单元测试:
public CompanyDTO update(CompanyRequest companyRequest, UUID uuid) {
final Company company = companyRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException("Not found"));
company.setName(companyRequest.getName());
final Company saved = companyRepository.save(company);
return new CompanyDTO(saved);
}
我创建了以下单元测试:
@InjectMocks
private CompanyServiceImpl companyService;
@Mock
private CompanyRepository companyRepository;
@Captor
ArgumentCaptor<Company> captor;
@Test
public void testUpdate() {
final Company company = new Company();
company.setName("Company Name");
final UUID uuid = UUID.randomUUID();
final CompanyRequest request = new CompanyRequest();
request.setName("Updated Company Name");
when(companyRepository.findByUuid(uuid))
.thenReturn(Optional.ofNullable(company));
when(companyRepository.save(company)).thenReturn(company);
CompanyDTO result = companyService.update(request, uuid);
/* here we get the "company" parameter value that we send to save method
in the service. However, the name value of this paremeter is already
changed before passing to save method. So, how can I check if the old
and updated name value? */
Mockito.verify(companyRepository).save(captor.capture());
Company savedCompany = captor.getValue();
assertEquals(request.getName(), savedCompany.getName());
}
据我所知,我们使用 ArgumentCaptor
来捕获我们传递给方法的值。在这个例子中,我需要在正确的时间捕获值,并将发送到更新方法的名称的更新值与更新后返回的名称 属性 的值进行比较。但是,我找不到如何正确测试它并为我的测试方法添加必要的评论。那么,我应该如何使用 ArgumentCaptor
来验证我的更新方法使用给定值(“更新的公司名称”)更新公司。
下面是我将如何编写此测试用例,并以代码注释的形式进行解释。
@Test
public void testUpdate() {
// we make this a mock so we can analyze it later
final Company company = mock(Company.class);
// no need to have the same String literal twice
final String updatedName = "Updated Company Name";
// we make this a mock because only that one method is used
// if you create an actual object, you'll need to adjust this test
// when the constructor changes later
final CompanyRequest request = mock(CompanyRequest.class);
when(request.getName()).thenReturn(updatedName);
// we don't really care about the actual uuid, so any() will do here
when(companyRepository.findByUuid(any()))
.thenReturn(Optional.ofNullable(company));
when(companyRepository.save(any())).thenReturn(company);
// setup complete, let's go
CompanyDTO result = companyService.update(request, UUID.randomUUID());
// we want to make sure the name change has been applied
Mockito.verify(company.setName(udpatedName);
// make sure it has been saved as well
Mockito.verify(companyRepository).save(company);
// verify that the returned dto actually contains the company we've been working on
Company savedCompany = result.getCompany();
assertSame(savedCompany, company);
}
请注意,这并没有回答您关于如何使用参数捕获器的实际问题,但那是因为那是一个 X-Y 问题。
这是您 ArgumentCaptor
.
的场景
被测代码:
public void createProduct(String id) {
Product product = new Product(id);
repository.save(product);
}
请注意,a) 我们在测试代码中创建了一个对象,b) 我们想要验证该对象的特定内容,以及 c) 在调用之后我们无权访问该对象。这些几乎就是您需要俘虏的确切情况。
你可以这样测试:
void testCreate() {
final String id = "id";
ArgumentCaptor<Product> captor = ArgumentCaptor.for(Product.class);
sut.createProduct(id);
// verify a product was saved and capture it
verify(repository).save(captor.capture());
final Product created = captor.getValue();
// verify that the saved product which was captured was created correctly
assertThat(created.getId(), is(id));
}
我正在尝试为以下服务方法创建单元测试:
public CompanyDTO update(CompanyRequest companyRequest, UUID uuid) {
final Company company = companyRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException("Not found"));
company.setName(companyRequest.getName());
final Company saved = companyRepository.save(company);
return new CompanyDTO(saved);
}
我创建了以下单元测试:
@InjectMocks
private CompanyServiceImpl companyService;
@Mock
private CompanyRepository companyRepository;
@Captor
ArgumentCaptor<Company> captor;
@Test
public void testUpdate() {
final Company company = new Company();
company.setName("Company Name");
final UUID uuid = UUID.randomUUID();
final CompanyRequest request = new CompanyRequest();
request.setName("Updated Company Name");
when(companyRepository.findByUuid(uuid))
.thenReturn(Optional.ofNullable(company));
when(companyRepository.save(company)).thenReturn(company);
CompanyDTO result = companyService.update(request, uuid);
/* here we get the "company" parameter value that we send to save method
in the service. However, the name value of this paremeter is already
changed before passing to save method. So, how can I check if the old
and updated name value? */
Mockito.verify(companyRepository).save(captor.capture());
Company savedCompany = captor.getValue();
assertEquals(request.getName(), savedCompany.getName());
}
据我所知,我们使用 ArgumentCaptor
来捕获我们传递给方法的值。在这个例子中,我需要在正确的时间捕获值,并将发送到更新方法的名称的更新值与更新后返回的名称 属性 的值进行比较。但是,我找不到如何正确测试它并为我的测试方法添加必要的评论。那么,我应该如何使用 ArgumentCaptor
来验证我的更新方法使用给定值(“更新的公司名称”)更新公司。
下面是我将如何编写此测试用例,并以代码注释的形式进行解释。
@Test
public void testUpdate() {
// we make this a mock so we can analyze it later
final Company company = mock(Company.class);
// no need to have the same String literal twice
final String updatedName = "Updated Company Name";
// we make this a mock because only that one method is used
// if you create an actual object, you'll need to adjust this test
// when the constructor changes later
final CompanyRequest request = mock(CompanyRequest.class);
when(request.getName()).thenReturn(updatedName);
// we don't really care about the actual uuid, so any() will do here
when(companyRepository.findByUuid(any()))
.thenReturn(Optional.ofNullable(company));
when(companyRepository.save(any())).thenReturn(company);
// setup complete, let's go
CompanyDTO result = companyService.update(request, UUID.randomUUID());
// we want to make sure the name change has been applied
Mockito.verify(company.setName(udpatedName);
// make sure it has been saved as well
Mockito.verify(companyRepository).save(company);
// verify that the returned dto actually contains the company we've been working on
Company savedCompany = result.getCompany();
assertSame(savedCompany, company);
}
请注意,这并没有回答您关于如何使用参数捕获器的实际问题,但那是因为那是一个 X-Y 问题。
这是您 ArgumentCaptor
.
被测代码:
public void createProduct(String id) {
Product product = new Product(id);
repository.save(product);
}
请注意,a) 我们在测试代码中创建了一个对象,b) 我们想要验证该对象的特定内容,以及 c) 在调用之后我们无权访问该对象。这些几乎就是您需要俘虏的确切情况。
你可以这样测试:
void testCreate() {
final String id = "id";
ArgumentCaptor<Product> captor = ArgumentCaptor.for(Product.class);
sut.createProduct(id);
// verify a product was saved and capture it
verify(repository).save(captor.capture());
final Product created = captor.getValue();
// verify that the saved product which was captured was created correctly
assertThat(created.getId(), is(id));
}