例如,我在UserService中有此方法:
@Override
@Transactional
public UserDto create(UserDto userDto) {
User dbUser = userRepository.findOne(userDto.getId());
if (dbUser != null) {
throw new AuthException(AuthException.ErrorCode.DUPLICATE_USER_EXCEPTION);
}
User oneByLogin = userRepository.findOneByLogin(userDto.getLogin());
if (oneByLogin != null) {
throw new AuthExceptionAuthException.ErrorCode.DUPLICATE_LOGIN_EXCEPTION);
}
User newUser = new User();
newUser.setGuid(UUID.randomUUID().toString());
newUser.setInsertDate(new Date());
newUser.setFirstName(userDto.getFirstName());
newUser.setLastName(userDto.getLastName());
newUser.setLogin(userDto.getLogin());
newUser.setPassword(userDto.getPassword());
newUser.setAuthToken(TokenGenerator.nextToken());
newUser.setAuthTokenCreatedDate(new Date());
User savedUser = userRepository.save(newUser);
userDto.setAuthToken(savedUser.getAuthToken());
log.info("User {0} created", savedUser.getLogin());
return userDto;
}
如何为该方法创建单元测试?我接下来尝试了:
@Test
public void createUser() {
UserDto userDtoRequest = new UserDto();
userDtoRequest.setLogin("Alex");
userDtoRequest.setPassword("123");
UserDto found = userService.create(userDtoRequest);
assertThat(found.getAuthToken()).isNotEmpty();
}
我有下一个逻辑:
User dbUser = userRepository.findOne(userDto.getId());
dbUser = NULL if (dbUser != null
)和if (oneByLogin != null)
跳过User savedUser = userRepository.save(newUser);
savedUser = NULL 在这一步上,我遇到了一个问题,因为我无法模拟userRepository.save(newUser)
。
newUser create inside the method. and test fail.
savedUser.getAuthToken()-savedUser == NULL
我可以重写:
userRepository.save(newUser);
userDto.setAuthToken(newUser.getAuthToken());
log.info("User {0} created", newUser.getLogin());
return userDto;
但是如果我想使用返回的对象savedUser
怎么办?
答案 0 :(得分:2)
您可以执行以下操作:
@RunWith(MockitoJUnitRunner.class)
public class SimpleTest {
@Mock
private UserRepository mockedUserRepository;
// .. your test setup
@Test
public void testYourMethod() {
User userToReturnFromRepository = new User();
userToReturnFromRepository.setAuthToken(YOUR_TOKEN);
when(mockedUserRepository.save(any(UserDto.class)).thenReturn(userToReturnFromRepository);
UserDto found = userService.create(userDtoRequest);
// ... your asserts
}
}
使用这种方法,您只需确保将mockedUserRepository
注入到要测试的类中(例如,在构造函数中)。
答案 1 :(得分:0)
您需要编写多个测试用例才能测试不同的场景。
方案1: findOne 返回不为空的对象时:
@Test(expected=AuthException.class)
public void testCreateUserWhenAvailable() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(new User());
userService.create(userDto);
}
方案2: findOneByLogin 返回空对象时:
@Test(expected=AuthException.class)
public void testCreateUserWhenLoginAvailable() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(new User());
userService.create(userDto);
}
方案2:保存完成后:
@Test
public void testCreateUserWhenSaved() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(null);
//Create sample User object and set all the properties
User newUser=new User();
when(mockedUserRepository.save(Mockito.any(User.class)).thenReturn(newUser);
User returnedUser=userService.create(userDto);
//You have two ways to test, you can either verify that save method was invoked by
//verify method
verify(mockedUserRepository, times(1)).save(Mockito.any(User.class);
//or by assertion statements, match the authToken in the returned object to be equal
//to the one set by you in the mocked object
Assert.assertEquals(returnedUser.getAuthToken(),newUser.getAuthToken());
}
答案 2 :(得分:0)
您需要执行此操作。
library(shiny)
library(shinyFiles)
ui <- fluidPage(
shinyFilesButton("GetFile", "Choose a file" ,
title = "Please select a file:", multiple = FALSE,
buttonType = "default", class = NULL),
actionButton(inputId = "reload", label = "Reload data"),
tableOutput("test")
)
server <- function(input,output,session){
volumes <- getVolumes()
v = reactiveValues(path = NULL)
observe({
shinyFileChoose(input, "GetFile", roots = volumes, session = session)
if (!is.null(input$GetFile)) {
file_selected <- parseFilePaths(volumes, input$GetFile)
v$path <- as.character(file_selected$datapath)
req(v$path)
v$data <- read.csv(v$path)
}
})
observeEvent(input$reload, {
req(v$path)
v$data <- read.csv(v$path)
})
output$test <- renderTable({
print(v$path)
if (is.null(v$data)) return()
v$data
})
}
shinyApp(ui = ui, server = server)
现在您可以获取作为参数传递的用户。
答案 3 :(得分:0)
关于如何创建JPA存储库save
方法以及如何为带有@GeneratedValue
的字段生成随机ID的问题,我只差了两分钱。
/**
* Mocks {@link JpaRepository#save(Object)} method to return the
* saved entity as it was passed as parameter and add generated ID to it.
* If ID could not be generated, it will be ignored.
* If parameter already has and ID, it will be overridden.
*/
private <T, V> void mockSave(JpaRepository<T, V> repository) {
when(repository.save(any())).thenAnswer(i -> {
Object argument = i.getArgument(0);
Arrays.stream(argument.getClass().getDeclaredFields())
.filter(f -> f.getAnnotation(GeneratedValue.class) != null)
.forEach(f -> enrichGeneratedValueField(argument, f));
return argument;
});
}
因此,在这里您将所需的存储库作为参数传递,并且方法对所有带有enrichGeneratedValueField
注释的字段调用@GeneratedValue
。这是此方法的实现:
private void enrichGeneratedValueField(Object argument, Field field) {
try {
if (field.getType().isAssignableFrom(Integer.class)) {
FieldUtils.writeField(field, argument, Math.abs(random.nextInt()), true);
} else {
FieldUtils.writeField(field, argument, mock(field.getType()), true);
}
} catch (Exception ignored) {
}
}
在此示例中,我仅使用Integer
类型的ID,但可以随意添加以添加所需的ID类型。