本文介紹了如何與其約束驗證器一起對方法進行單元測試(哪些應該被刪除)?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我的應用程序有一個由CDI應用程序作用域Bean組成的服務層:
@ApplicationScoped
@Transactional
public class PostService {
@Inject private PostRepository postRepo;
@Inject private UserRepository userRepo;
@Inject private SectionRepository sectionRepo;
@Inject private LoggedInUser loggedInUser;
public PostDto getPost(@PostExists int id){
Post p = postRepo.findById(id);
//create post DTO from p
return post;
}
public void delete(@PostExists int id){
postRepo.remove(postRepo.findById(id));
}
public int newPost(@NotBlank @Max(255) String title,
@Max(2000) String body,
@SectionExists String sectionName){
User user = userRepo.getByName(loggedInUser.getUsername());
Section section = sectionRepo.getByName(sectionName);
Post post = new Post();
post.setTitle(title);
post.setContent(body == null || body.isBlank() ? "" : body);
post.setAuthor(user);
post.setSection(section);
post.setType(TEXT);
return postRepo.insert(post).getId();
}
}
當一個方法被調用時,攔截器(在我的例子中是來自ApacheBVal的BValInterceptor.class
)通過檢查注釋并相應地驗證參數來檢查該方法契約是否被遵守。
如您所見,有一些可能命中數據庫的自定義約束,如@SectionExists
、@PostExists
:
public class SectionExistsValidator implements ConstraintValidator<SectionExists, String> {
@Inject SectionRepository sectionRepo;
@Override
public void initialize(SectionExists constraintAnnotation) {}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return (sectionRepo.getByName(value) != null);
}
}
public class PostExistsValidator implements ConstraintValidator<PostExists, Integer> {
@Inject PostRepository postRepo;
@Override
public void initialize(PostExists constraintAnnotation) {}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return (postRepo.findById(value) != null);
}
}
我想做的是對我的業務方法(getpost
、delete
、newPost
)和它的驗證器一起進行單元測試。應該模擬可能命中數據庫的驗證器(或者應該模擬它們的依賴項)。
我如何才能做到這一點?如何才能使注入(和模擬注入)在單元測試中對驗證器起作用?
以下是我使用的內容:
Tomee 8.0.8
用于Bean驗證的Apache BVal JSR 303/JSR380(包括在Tomee中)
用于CDI的Apache OpenWebBeans(包括在Tomee中)
JUnit5
Mockito
我可以使用OpenEJB’s ApplicationComposer或Arquillian運行嵌入式容器。但是,我從未使用過Arquillian。
cdi
最終我選擇了this really cool library (cdimock),這正是我所需要的:將推薦答案放在一個定制的cdi作用域中,這樣相同的模擬實例就可以注入到測試用例中的其他Bean中。這樣的事情也可以通過cdi-unit@Produces @Mock
注釋來實現(盡管我沒有親自嘗試過,因為它只支持Weld)
這是我的測試類的代碼:
@RunWithApplicationComposer(mode = ExtensionMode.PER_EACH)
@ExtendWith({MockitoExtension.class, CdiMocking.class})
@MockitoSettings(strictness = LENIENT)
@Classes(cdi = true,
value={PostService.class},
cdiInterceptors = BValInterceptor.class,
cdiStereotypes = CdiMock.class)
public class PostServiceTest {
@Mock SectionRepository sectionRepository;
@Mock PostRepository postRepository;
@Mock UserRepository userRepository;
@Inject PostService service;
@BeforeEach
void setUp() {}
@AfterEach
void tearDown() {}
@Test
public void noSectionFoundNewPost(){
String sectionName = "idontexist";
when(sectionRepository.getByName(sectionName)).thenReturn(null);
assertThrows(ConstraintViolationException.class,
() -> service.newPost("title", "body", sectionName));
}
}
在代碼中,我使用的是OpenEJB的應用程序編寫器,但我可以輕松切換到任何嵌入式CDI容器
這篇關于如何與其約束驗證器一起對方法進行單元測試(哪些應該被刪除)?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,