Java 从单元测试中消除null的方法
当我尝试连接此url时,我在方法中使用Java 从单元测试中消除null的方法,java,unit-testing,mockito,Java,Unit Testing,Mockito,当我尝试连接此url时,我在方法中使用url变量获取NPE(使用givenTitle将其解析为null) 我应该怎么做才能使url不为空 堆栈跟踪: java.lang.NullPointerException at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769) at java.base/java.util.regex.Matcher.reset(Matcher.java:416) a
url
变量获取NPE(使用givenTitle
将其解析为null)
我应该怎么做才能使url不为空
堆栈跟踪:
java.lang.NullPointerException
at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)
at java.base/java.util.regex.Matcher.reset(Matcher.java:416)
at java.base/java.util.regex.Matcher.<init>(Matcher.java:253)
at java.base/java.util.regex.Pattern.matcher(Pattern.java:1130)
at java.base/java.util.Formatter.parse(Formatter.java:2698)
at java.base/java.util.Formatter.format(Formatter.java:2653)
at java.base/java.util.Formatter.format(Formatter.java:2607)
at java.base/java.lang.String.format(String.java:2734)
at bookstore.scraper.book.booksource.empik.EmpikSource.concatUrlWithTitle(EmpikSource.java:154)
at bookstore.scraper.book.booksource.empik.EmpikSource.getMostPreciseBook(EmpikSource.java:74)
at bookstore.scraper.book.booksource.empik.EmpikSourceTest.getMostPreciseBook(EmpikSourceTest.java:66)
备选案文1:
将新方法getCategory
添加到empikUrlProperties
公共字符串getCategory(CategoryType类别){
断言(类别!=null);
开关(类别){
案件类别类型.犯罪:
返回getCrime();
案例类别类型。畅销书:
返回畅销书();
案例类别类型。传记:
返回get传记();
case CategoryType.FANTASY:
返回getFantasy();
案例类别类型.GUIDES:
返回getGuides();
案例分类类型。最精确的书籍:
返回getMostPreciseBook();
案例类别类型.ROMANCES:
返回getRomances();
违约:
抛出新的IllegalArgumentException(“意外类别:”+类别)
}
}
对于现在的测试,您只需模拟它
when(empikUrlProperties.getCategory(CategoryType.CRIME))
.然后返回(“https://www.empik.com/%s,%s,ksiazka-p”);
备选案文2: 更改构造函数以接受来自外部的映射。 这意味着您将映射创建移动到另一个类/函数, 它在其他地方创建了地图 在这种情况下,您需要手动注入模拟(不要使用
@InjectMocks
),
因为你不应该嘲笑一个集合
(对于这一部分,我不确定@Autowired将如何处理它,也许您需要将它包装到另一个类中。setter可能是更合适的选项。)
@Autowired
公共EmpikSource(EmpikUrlProperties EmpikUrlProperties,JSoupConnector JSoupConnector,Map categoryToEmpikURL){
this.empikUrlProperties=empikUrlProperties;
this.jSoupConnector=jSoupConnector;
categoryToEmpikURL=categoryToEmpikURL;
}
选项1:
将新方法getCategory
添加到empikUrlProperties
公共字符串getCategory(CategoryType类别){
断言(类别!=null);
开关(类别){
案件类别类型.犯罪:
返回getCrime();
案例类别类型。畅销书:
返回畅销书();
案例类别类型。传记:
返回get传记();
case CategoryType.FANTASY:
返回getFantasy();
案例类别类型.GUIDES:
返回getGuides();
案例分类类型。最精确的书籍:
返回getMostPreciseBook();
案例类别类型.ROMANCES:
返回getRomances();
违约:
抛出新的IllegalArgumentException(“意外类别:”+类别)
}
}
对于现在的测试,您只需模拟它
when(empikUrlProperties.getCategory(CategoryType.CRIME))
.然后返回(“https://www.empik.com/%s,%s,ksiazka-p”);
备选案文2: 更改构造函数以接受来自外部的映射。 这意味着您将映射创建移动到另一个类/函数, 它在其他地方创建了地图 在这种情况下,您需要手动注入模拟(不要使用
@InjectMocks
),
因为你不应该嘲笑一个集合
(对于这一部分,我不确定@Autowired将如何处理它,也许您需要将它包装到另一个类中。setter可能是更合适的选项。)
@Autowired
公共EmpikSource(EmpikUrlProperties EmpikUrlProperties,JSoupConnector JSoupConnector,Map categoryToEmpikURL){
this.empikUrlProperties=empikUrlProperties;
this.jSoupConnector=jSoupConnector;
categoryToEmpikURL=categoryToEmpikURL;
}
空url来自地图类别ToEmpikURL。此映射由方法createCategoryToEmpikURLMap()创建。但是你没有发布tat方法。@JBNizet Ye,但是这个方法是私有的,因为我不需要在外部发布。我在考虑一些变通办法,但没有想出任何好主意。我应该把它换成公共的吗?@JBNizet啊,对不起。误解了你的评论。我已经添加了这个方法。所以,您需要再次查看您的代码在做什么。它在构造器内部的映射中填充来自属性的值。属性是一个构造函数参数。在测试中何时调用该构造函数?由于InjectMocks注释,它由Mockito调用。什么作为参数传递?嘲弄。默认情况下,mock返回null。因此构造函数在映射中存储空值。我会删除无用的映射,直接从属性中获取值。通过这种方式,您可以在调用测试中的方法之前告诉您的模拟返回什么。或者更好的是,甚至不要对属性使用模拟,因为它是一个POJO,您可以自己填充。空url来自Map categoryToEmpikURL。此映射由方法createCategoryToEmpikURLMap()创建。但是你没有发布tat方法。@JBNizet Ye,但是这个方法是私有的,因为我不需要在外部发布。我在考虑一些变通办法,但没有想出任何好主意。我应该把它换成公共的吗?@JBNizet啊,对不起。误解了你的评论。我已经添加了这个方法。所以,您需要再次查看您的代码在做什么。它在构造器内部的映射中填充来自属性的值。属性是一个构造函数参数。在测试中何时调用该构造函数?由于InjectMocks注释,它由Mockito调用。什么作为参数传递?嘲弄。默认情况下,mock返回null。因此构造函数在映射中存储空值。我会删除无用的映射,直接从属性中获取值。这样,您可以在调用被测方法之前告诉您的mock要返回什么。或者更好的是,甚至不要对属性使用mock,因为它是一个POJO,您可以只填充自己
package bookstore.scraper.book.booksource.empik;
import bookstore.scraper.book.Book;
import bookstore.scraper.enums.CategoryType;
import bookstore.scraper.urlproperties.EmpikUrlProperties;
import bookstore.scraper.utilities.JSoupConnector;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import static bookstore.scraper.dataprovider.EmpikBookProvider.prepare15CrimeBooks;
import static bookstore.scraper.dataprovider.EmpikBookProvider.prepareMostPreciseBook;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EmpikSourceTest {
@Mock
JSoupConnector jSoupConnector;
@Mock
EmpikUrlProperties empikUrlProperties;
@InjectMocks
EmpikSource empikSource;
/*@Before
public void setUp() {
when(empikUrlProperties.getConcreteBook()).thenReturn(anyString());
}
*/
@Test
public void getMostPreciseBook() throws IOException {
File in = getFile("/empik/MostPreciseBookEmpik.html");
Document empikDocument = Jsoup.parse(in, "UTF-8");
when(jSoupConnector.connect(any())).thenReturn(empikDocument);
when(empikUrlProperties.getConcreteBook()).thenReturn("https://www.empik.com/%s,%s,ksiazka-p");
Book actualBooks = empikSource.getMostPreciseBook("W pustyni i w puszczy. Lektura z opracowaniem - Henryk Sienkiewicz");
Book expectedBooks = prepareMostPreciseBook();
assertEquals(expectedBooks, actualBooks);
}
private File getFile(String resourceName) {
try {
return new File(EmpikSourceTest.class.getResource(resourceName).toURI());
} catch (URISyntaxException e) {
throw new IllegalStateException(e);
}
}
}
java.lang.NullPointerException
at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)
at java.base/java.util.regex.Matcher.reset(Matcher.java:416)
at java.base/java.util.regex.Matcher.<init>(Matcher.java:253)
at java.base/java.util.regex.Pattern.matcher(Pattern.java:1130)
at java.base/java.util.Formatter.parse(Formatter.java:2698)
at java.base/java.util.Formatter.format(Formatter.java:2653)
at java.base/java.util.Formatter.format(Formatter.java:2607)
at java.base/java.lang.String.format(String.java:2734)
at bookstore.scraper.book.booksource.empik.EmpikSource.concatUrlWithTitle(EmpikSource.java:154)
at bookstore.scraper.book.booksource.empik.EmpikSource.getMostPreciseBook(EmpikSource.java:74)
at bookstore.scraper.book.booksource.empik.EmpikSourceTest.getMostPreciseBook(EmpikSourceTest.java:66)
package bookstore.scraper.urlproperties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Getter
@Setter
@Component
@ConfigurationProperties("external.library.url.empik")
public class EmpikUrlProperties {
private String mostPreciseBook;
private String bestSellers;
private String concreteBook;
private String romances;
private String biographies;
private String crime;
private String guides;
private String fantasy;
}