You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构造方法异常测试未达预期,如何捕获FileNotFoundException?

问题:CSV读取类的单元测试异常捕获失败

我有一段从CSV文件读取数据的代码,需要编写单元测试,但不知如何着手。

原代码如下:

public class BudgetTags implements BudgetTagsList{
    // State variables
    private Set<String> tags = new TreeSet<>();
    private String tag_file_path;

    public BudgetTags(String tag_file_path){
        //Retrieve tags from tag file
        this.tag_file_path = tag_file_path;
        this.retrieveTags();
    }
public void retrieveTags() {
        String line = "";
        try{
            // Begin reading each line
            BufferedReader br = new BufferedReader(new FileReader(this.tag_file_path ));
            while((line = br.readLine()) != null){
                String[] row = line.split(",");
                this.tags.add(row[0]); //Assume correct file format
            }
            br.close();
        } catch (IOException e){
            System.out.println("Fatal exception: "+ e.getMessage());
        }
    }
}

需注意,retrieveTags()方法因FileNotFoundException继承自IOException,无法单独声明抛出该异常。我当前的测试代码如下:

@Test
@DisplayName("File name doesn't exist")
void testRetrieveTag3() {
    String path = "test\\no_file.csv";

    //Instantiate new tags object
    BudgetTags tags = new BudgetTags(path);
    IOException thrown = assertThrows(IOException.class, () -> tags.retrieveTags());
}

由于path指向的文件不存在,我预期测试能捕获IOException(更希望捕获FileNotFoundException),但运行测试时却收到AssertionFailedError。请问如何重构测试,以在实例化BudgetTags对象时捕获FileNotFoundException?


解决方法

问题根源是retrieveTags()方法内部捕获了IOException但没有重新抛出,测试代码调用它时根本不会向外抛出异常,assertThrows自然会失败。要解决这个问题,需要先调整原代码的异常处理逻辑,再修改测试:

步骤1:调整原代码的异常处理

有两种可选的处理方式:

  • 方式一:将异常向上抛出
    修改retrieveTags()的方法签名,声明抛出IOException(自动包含FileNotFoundException子类),同时去掉内部的catch块,或在catch中重新抛出异常:

    public void retrieveTags() throws IOException {
        String line = "";
        try (BufferedReader br = new BufferedReader(new FileReader(this.tag_file_path))) {
            while((line = br.readLine()) != null){
                String[] row = line.split(",");
                this.tags.add(row[0]);
            }
        }
        // 若需要保留日志,可改为:
        // try { ... } catch (IOException e) {
        //     System.out.println("Fatal exception: "+ e.getMessage());
        //     throw e;
        // }
    }
    

    同时构造方法也需要声明抛出IOException,因为它调用了retrieveTags():

    public BudgetTags(String tag_file_path) throws IOException {
        this.tag_file_path = tag_file_path;
        this.retrieveTags();
    }
    
  • 方式二:保存异常状态(不抛出检查型异常)
    如果不想抛出检查型异常,可以在类中添加成员变量保存异常状态:

    private IOException loadException;
    
    public void retrieveTags() {
        String line = "";
        loadException = null;
        try (BufferedReader br = new BufferedReader(new FileReader(this.tag_file_path))) {
            while((line = br.readLine()) != null){
                String[] row = line.split(",");
                this.tags.add(row[0]);
            }
        } catch (IOException e){
            loadException = e;
            System.out.println("Fatal exception: "+ e.getMessage());
        }
    }
    
    public IOException getLoadException() {
        return loadException;
    }
    

步骤2:修改单元测试

根据上面的代码调整,测试也需要对应修改:

对应方式一的测试代码

构造方法会抛出异常,直接在构造对象时捕获即可:

@Test
@DisplayName("File name doesn't exist - should throw FileNotFoundException")
void testRetrieveTag3() {
    String path = "test\\no_file.csv";

    FileNotFoundException thrown = assertThrows(FileNotFoundException.class, () -> {
        new BudgetTags(path); // 构造时调用retrieveTags,会抛出异常
    });
    
    // 可选:验证异常信息
    assertNotNull(thrown.getMessage());
}

对应方式二的测试代码

不需要捕获异常,而是检查保存的异常状态:

@Test
@DisplayName("File name doesn't exist - should record FileNotFoundException")
void testRetrieveTag3() {
    String path = "test\\no_file.csv";
    BudgetTags tags = new BudgetTags(path);
    
    assertNotNull(tags.getLoadException());
    assertTrue(tags.getLoadException() instanceof FileNotFoundException);
}

额外建议

尽量使用try-with-resources语法简化IO资源管理,它会自动关闭资源,避免手动关闭的遗漏,代码更简洁安全。

内容的提问来源于stack exchange,提问作者J_code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:35:29