Java 方法不会抛出JUnit5测试用例
我有一个定制的Log4j appender,它作为一个单例类实现,在调用类的Java 方法不会抛出JUnit5测试用例,java,log4j,tdd,junit5,assertion,Java,Log4j,Tdd,Junit5,Assertion,我有一个定制的Log4j appender,它作为一个单例类实现,在调用类的getInstance()方法时需要一个布局对象。 我编写了一个JUnit5测试用例来测试在未设置布局对象时是否引发异常。如果没有设置布局,我抛出了一个IllegalArgumentException 下面的代码在执行时引发异常 public class App { public static void main(String[] args){ Logger logger = Logger.get
getInstance()
方法时需要一个布局对象。
我编写了一个JUnit5测试用例来测试在未设置布局对象时是否引发异常。如果没有设置布局,我抛出了一个IllegalArgumentException
下面的代码在执行时引发异常
public class App {
public static void main(String[] args){
Logger logger = Logger.getLogger("test");
CustomAppender m = CustomAppender.getInstance();
logger.addAppender(m);
logger.info("test"); // Exception is thrown by this statement
}
}
但是,下面的测试用例失败。事实上,没有抛出异常
@Test
public void testException(){
Logger logger = Logger.getLogger("test");
CustomAppender m = CustomAppender.getInstance();
logger.addAppender(m);
assertThrows(Exception.class, () -> {
logger.info("test");
});
}
我错过了什么
编辑:来自CustomAppender
类的更多代码
private CustomAppender(Layout layout, ArrayList<LoggingEvent> list) {
cLayout = layout;
eventsList = list;
discardedLogCount = 0;
super.setLayout(cLayout);
}
// Instance with a user-defined list and a layout
public static CustomAppender getInstance(Layout layout, ArrayList<LoggingEvent> list) {
if (INSTANCE == null) {
// Thread-safety
synchronized (CustomAppender.class) {
INSTANCE = new CustomAppender(layout, list);
}
}
return INSTANCE;
}
// Instance with an empty list
public static CustomAppender getInstance(Layout layout){
return CustomAppender.getInstance(layout, new ArrayList<>());
}
// Instance with a null layout
public static CustomAppender getInstance(ArrayList<LoggingEvent> list){
return CustomAppender.getInstance(null, list);
}
// Default instance
public static CustomAppender getInstance(){
return CustomAppender.getInstance(null, new ArrayList<>());
}
// Appends at most maxSize items
@Override
protected void append(LoggingEvent event) throws IllegalArgumentException {
if (this.cLayout == null)
throw new IllegalArgumentException();
if (eventsList.size() < maxSize) {
eventsList.add(event);
} else {
// Remove the oldest item and add a new one
eventsList.remove(0);
discardedLogCount++;
eventsList.add(event);
}
}
private CustomAppender(布局、阵列列表){
cLayout=布局;
事件列表=列表;
discardedLogCount=0;
超级设置布局(cLayout);
}
//具有用户定义的列表和布局的实例
公共静态CustomAppender getInstance(布局、ArrayList列表){
if(实例==null){
//线程安全
已同步(CustomAppender.class){
实例=新的CustomAppender(布局、列表);
}
}
返回实例;
}
//具有空列表的实例
公共静态CustomAppender getInstance(布局){
返回CustomAppender.getInstance(布局,新ArrayList());
}
//具有空布局的实例
公共静态CustomAppender getInstance(ArrayList列表){
返回CustomAppender.getInstance(null,list);
}
//默认实例
公共静态CustomAppender getInstance(){
返回CustomAppender.getInstance(null,new ArrayList());
}
//最多追加maxSize项
@凌驾
受保护的void append(LoggingEvent事件)引发IllegalArgumentException{
如果(this.cLayout==null)
抛出新的IllegalArgumentException();
if(eventsList.size()
如果未传递Layout
参数,是否从CustomAppender.getInstance()
抛出IllegalArgumentException
?或者你要等到调用了Logger.info()
之后再开始吗?不,我知道这是违反直觉的,但这是作业中要求的。相反,我在重载的append()
方法中执行先决条件检查,该方法在执行Logger.info()
时调用。我使用了一个调试器并验证了我的前提条件检查(即,如果我的私有布局对象为null,则抛出一个异常)工作正常,但由于某种原因测试失败。事实上,如果我对assertThrow()
调用进行注释,并且只执行logger.info()
,它就可以正常工作。它会按预期抛出异常
?它不会失败,因为您的测试没有被隔离。如果您已经在CustomAppender
上至少调用了一次getInstance
,并给它一些Layout
,那么从那时起,您将获得该布局的实例。由于INSTANCE
字段是静态的,所以该行为会一直持续到类加载器垃圾回收为止,对于您的测试来说,这可能是“永远的”。您应该以某种方式显式地创建所需的appender,而不是依赖于您的测试第一个调用该方法。如果您的实例实际上是用外部的东西参数化的,因此不是一个单例,而是一个Layout->Appender
的缓存工厂,那么为什么要遵循单例模式呢?如果您希望通过调用代码将其视为单例,但在启动时仍为配置打开,则必须拆分关注点,并且不要让getInstance()
也初始化单例。还有另一种方法,比如init(Layout,List)
,这样您也可以在测试中使用init
方法,甚至在测试后进行清理。