JUnit 测试模拟对象返回空值
JUnit Tests Mocked Objects are returning null values
我正在尝试 运行 在使用配置 Class 和 RestTemplate Class 的服务层上进行 JUnit 测试。但是,每当我尝试 运行 测试时,我的配置和服务方法的 return 值都会得到空值。
这是我的服务class:
package com.blogposts.assessment.restapi;
import com.blogposts.assessment.classes.Post;
import com.blogposts.assessment.classes.Posts;
import com.blogposts.assessment.exceptions.BadInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/*
This is a Service component in Spring Boot that implements the business logic for the api. It de-duplicates posts in
the list and implements sort based on the parameters received from the rest controller.
*/
@Service
public class APIService {
private final RestTemplate restTemplate;
private final APIConfiguration apiConfig;
//This looks for the beans that were created for the APIConfiguration and the RestTemplate so it utilizes
//the same instance of those beans.
@Autowired
public APIService(RestTemplate restTemplate, APIConfiguration apiConfig) {
this.restTemplate = restTemplate;
this.apiConfig = apiConfig;
}
//Implements business logic on Get Request
public Posts getBlogPosts(String tags, String sortBy, String direction) throws ExecutionException, InterruptedException {
Posts consolidatedPosts = getBlogPostsWithMultipleTags(tags);
List<Post> listOfPosts = consolidatedPosts.getPosts();
//If direction is "asc" or blank, it sorts in an ascending manner
if (direction.equals("asc") || direction.equals("")) {
//Switch used to select how to sort
switch (sortBy) {
case "id":
Collections.sort(listOfPosts, Post.compareById);
break;
case "":
Collections.sort(listOfPosts, Post.compareById);
break;
case "likes":
Collections.sort(listOfPosts, Post.compareByLikes);
break;
case "reads":
Collections.sort(listOfPosts, Post.compareByReads);
break;
case "popularity":
Collections.sort(listOfPosts, Post.compareByPopularity);
break;
default:
throw new BadInputException("sortBy parameter is invalid");
}
}
//If direction is "desc", posts are sorted in reverse order.
else if (direction.equals("desc")) {
switch (sortBy) {
case "id":
Collections.sort(listOfPosts, Post.compareById.reversed());
break;
case "":
Collections.sort(listOfPosts, Post.compareById.reversed());
break;
case "likes":
Collections.sort(listOfPosts, Post.compareByLikes.reversed());
break;
case "reads":
Collections.sort(listOfPosts, Post.compareByReads.reversed());
break;
case "popularity":
Collections.sort(listOfPosts, Post.compareByPopularity.reversed());
break;
default:
throw new BadInputException("sortBy parameter is invalid");
}
}
//Throws exception if direction parameter is not desc, asc, or blank.
else {
throw new BadInputException("direction parameter is invalid");
}
return consolidatedPosts;
}
//This method conducts multiple get requests to the Hatchways API based on the number of tags included and
//de-duplicates the posts so that no post is repeated.
public Posts getBlogPostsWithMultipleTags(String tags) throws ExecutionException, InterruptedException {
//Checks to see if the tags parameter is left blank or is null
if(tags.equals("")) {
throw new BadInputException("The tags parameter is missing and cannot be null.");
}
//Splits the comma separated tags into an array of Strings
String[] tagsArray = tags.split(",");
//Utilizing a hashset to store each posts' id if it's added to the Posts object's List.
//Hashset was used because lookup time is O(1) with the blog id value.
Posts combinedPosts = new Posts();
Posts[] separatePosts = new Posts[tagsArray.length];
HashSet<Long> consolidatedPostIDs = new HashSet<Long>();
//Iterate through each tag and run a get request to the Hatchways API
for (int i = 0; i < tagsArray.length; i++) {
String url = apiConfig.getApiUrl() + "/?tag=" + tagsArray[i];
CompletableFuture<Posts> postsFuture = getBlogPostWithOneTag(tagsArray[i]);
separatePosts[i] = postsFuture.get();
}
// Loop through the Posts[] array to review each Posts object. Look at an individual post within each Posts object
// For each blog individual post, check to see if it's already in our combinedPosts object. If it is, ignore it, otherwise add
// it to the hashset and the combinedPosts object.
for (Posts posts : separatePosts) {
for(int i = 0; i < posts.getPosts().size(); i++) {
Post currentPost = posts.getPosts().get(i);
if(consolidatedPostIDs.contains(currentPost.getId())) {
continue;
} else {
combinedPosts.addPost(currentPost);
consolidatedPostIDs.add(currentPost.getId());
}
}
}
return combinedPosts;
}
@Async
public CompletableFuture<Posts> getBlogPostWithOneTag(String tag){
String url = apiConfig.getApiUrl() + "/?tag=" + tag;
Posts posts = restTemplate.getForObject(url,Posts.class);
return CompletableFuture.completedFuture(posts);
}
}
我正在尝试使用 Junit 测试和 Mockito 对此进行测试,但是当 canGetBlogPosts() 测试为 运行 时,它会为两个 System.out.println() 调用打印出空值。
package com.blogposts.assessment.restapi;
import com.blogposts.assessment.classes.Posts;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ExtendWith(MockitoExtension.class)
public class APIServiceTest {
@Mock
private RestTemplate restTemplate;
@Mock
private APIConfiguration apiConfiguration;
private APIService underTest;
@BeforeEach
void setUp() {
underTest = new APIService(restTemplate,apiConfiguration);
}
@Test
void canGetBlogPosts() throws ExecutionException, InterruptedException {
//when
System.out.println(apiConfiguration.getApiUrl());
CompletableFuture<Posts> posts = underTest.getBlogPostWithOneTag("science");
System.out.println(posts.get());
}
@Test
@Disabled
void getBlogPostsWithMultipleTags() {
}
@Test
@Disabled
void getBlogPostWithOneTag() {
}
}
很简单。您正在创建您的模拟,但您没有使用特殊的 mockito when-then
语法配置它们。
以下是您的操作方法。
如果您希望模拟在每个测试中都以相同的方式运行,则可以在 @BeforeEach
方法中执行此操作。或者您可以为每个测试单独配置它们。
这是基本语法。您可以获取详细信息 here.
List mockList = Mockito.mock(ArrayList.class);
Mockito.when(mockList.size()).thenReturn(100);
此外,您可能需要添加它以获取由 MockitoExtension
注入的模拟
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
这能解决您的问题吗?在评论中让我知道。
我正在尝试 运行 在使用配置 Class 和 RestTemplate Class 的服务层上进行 JUnit 测试。但是,每当我尝试 运行 测试时,我的配置和服务方法的 return 值都会得到空值。
这是我的服务class:
package com.blogposts.assessment.restapi;
import com.blogposts.assessment.classes.Post;
import com.blogposts.assessment.classes.Posts;
import com.blogposts.assessment.exceptions.BadInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/*
This is a Service component in Spring Boot that implements the business logic for the api. It de-duplicates posts in
the list and implements sort based on the parameters received from the rest controller.
*/
@Service
public class APIService {
private final RestTemplate restTemplate;
private final APIConfiguration apiConfig;
//This looks for the beans that were created for the APIConfiguration and the RestTemplate so it utilizes
//the same instance of those beans.
@Autowired
public APIService(RestTemplate restTemplate, APIConfiguration apiConfig) {
this.restTemplate = restTemplate;
this.apiConfig = apiConfig;
}
//Implements business logic on Get Request
public Posts getBlogPosts(String tags, String sortBy, String direction) throws ExecutionException, InterruptedException {
Posts consolidatedPosts = getBlogPostsWithMultipleTags(tags);
List<Post> listOfPosts = consolidatedPosts.getPosts();
//If direction is "asc" or blank, it sorts in an ascending manner
if (direction.equals("asc") || direction.equals("")) {
//Switch used to select how to sort
switch (sortBy) {
case "id":
Collections.sort(listOfPosts, Post.compareById);
break;
case "":
Collections.sort(listOfPosts, Post.compareById);
break;
case "likes":
Collections.sort(listOfPosts, Post.compareByLikes);
break;
case "reads":
Collections.sort(listOfPosts, Post.compareByReads);
break;
case "popularity":
Collections.sort(listOfPosts, Post.compareByPopularity);
break;
default:
throw new BadInputException("sortBy parameter is invalid");
}
}
//If direction is "desc", posts are sorted in reverse order.
else if (direction.equals("desc")) {
switch (sortBy) {
case "id":
Collections.sort(listOfPosts, Post.compareById.reversed());
break;
case "":
Collections.sort(listOfPosts, Post.compareById.reversed());
break;
case "likes":
Collections.sort(listOfPosts, Post.compareByLikes.reversed());
break;
case "reads":
Collections.sort(listOfPosts, Post.compareByReads.reversed());
break;
case "popularity":
Collections.sort(listOfPosts, Post.compareByPopularity.reversed());
break;
default:
throw new BadInputException("sortBy parameter is invalid");
}
}
//Throws exception if direction parameter is not desc, asc, or blank.
else {
throw new BadInputException("direction parameter is invalid");
}
return consolidatedPosts;
}
//This method conducts multiple get requests to the Hatchways API based on the number of tags included and
//de-duplicates the posts so that no post is repeated.
public Posts getBlogPostsWithMultipleTags(String tags) throws ExecutionException, InterruptedException {
//Checks to see if the tags parameter is left blank or is null
if(tags.equals("")) {
throw new BadInputException("The tags parameter is missing and cannot be null.");
}
//Splits the comma separated tags into an array of Strings
String[] tagsArray = tags.split(",");
//Utilizing a hashset to store each posts' id if it's added to the Posts object's List.
//Hashset was used because lookup time is O(1) with the blog id value.
Posts combinedPosts = new Posts();
Posts[] separatePosts = new Posts[tagsArray.length];
HashSet<Long> consolidatedPostIDs = new HashSet<Long>();
//Iterate through each tag and run a get request to the Hatchways API
for (int i = 0; i < tagsArray.length; i++) {
String url = apiConfig.getApiUrl() + "/?tag=" + tagsArray[i];
CompletableFuture<Posts> postsFuture = getBlogPostWithOneTag(tagsArray[i]);
separatePosts[i] = postsFuture.get();
}
// Loop through the Posts[] array to review each Posts object. Look at an individual post within each Posts object
// For each blog individual post, check to see if it's already in our combinedPosts object. If it is, ignore it, otherwise add
// it to the hashset and the combinedPosts object.
for (Posts posts : separatePosts) {
for(int i = 0; i < posts.getPosts().size(); i++) {
Post currentPost = posts.getPosts().get(i);
if(consolidatedPostIDs.contains(currentPost.getId())) {
continue;
} else {
combinedPosts.addPost(currentPost);
consolidatedPostIDs.add(currentPost.getId());
}
}
}
return combinedPosts;
}
@Async
public CompletableFuture<Posts> getBlogPostWithOneTag(String tag){
String url = apiConfig.getApiUrl() + "/?tag=" + tag;
Posts posts = restTemplate.getForObject(url,Posts.class);
return CompletableFuture.completedFuture(posts);
}
}
我正在尝试使用 Junit 测试和 Mockito 对此进行测试,但是当 canGetBlogPosts() 测试为 运行 时,它会为两个 System.out.println() 调用打印出空值。
package com.blogposts.assessment.restapi;
import com.blogposts.assessment.classes.Posts;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ExtendWith(MockitoExtension.class)
public class APIServiceTest {
@Mock
private RestTemplate restTemplate;
@Mock
private APIConfiguration apiConfiguration;
private APIService underTest;
@BeforeEach
void setUp() {
underTest = new APIService(restTemplate,apiConfiguration);
}
@Test
void canGetBlogPosts() throws ExecutionException, InterruptedException {
//when
System.out.println(apiConfiguration.getApiUrl());
CompletableFuture<Posts> posts = underTest.getBlogPostWithOneTag("science");
System.out.println(posts.get());
}
@Test
@Disabled
void getBlogPostsWithMultipleTags() {
}
@Test
@Disabled
void getBlogPostWithOneTag() {
}
}
很简单。您正在创建您的模拟,但您没有使用特殊的 mockito when-then
语法配置它们。
以下是您的操作方法。
如果您希望模拟在每个测试中都以相同的方式运行,则可以在 @BeforeEach
方法中执行此操作。或者您可以为每个测试单独配置它们。
这是基本语法。您可以获取详细信息 here.
List mockList = Mockito.mock(ArrayList.class);
Mockito.when(mockList.size()).thenReturn(100);
此外,您可能需要添加它以获取由 MockitoExtension
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
这能解决您的问题吗?在评论中让我知道。