Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 编写Junit测试以覆盖异常和捕获块_Java_Spring_Unit Testing_Junit_Junit4 - Fatal编程技术网

Java 编写Junit测试以覆盖异常和捕获块

Java 编写Junit测试以覆盖异常和捕获块,java,spring,unit-testing,junit,junit4,Java,Spring,Unit Testing,Junit,Junit4,我已经为以下函数编写了Junit测试用例。当检查JACOCO测试覆盖率时。它显示测试用例只覆盖了try块。我是编写测试用例的新手。如何在测试用例中涵盖异常和catch块 这里有一个方法 public static List<Student> readCsvFile(String fileName) { BufferedReader fileReader = null; //logic to read file } catch (Exception

我已经为以下函数编写了Junit测试用例。当检查JACOCO测试覆盖率时。它显示测试用例只覆盖了try块。我是编写测试用例的新手。如何在测试用例中涵盖异常和catch块

这里有一个方法

  public static List<Student> readCsvFile(String fileName)
    {

       BufferedReader fileReader = null;

//logic to read file    
}
catch (Exception e)
{
   System.out.println("Error in CsvFileReader !!!");
   e.printStackTrace();
        } finally
        {
            try
            {
                fileReader.close();
            } catch (IOException e)
            {
                System.out.println("Error while closing fileReader !!!");
                e.printStackTrace();
            }
        }
        return students;
    }
公共静态列表readCsvFile(字符串文件名)
{
BufferedReader fileReader=null;
//读取文件的逻辑
}
捕获(例外e)
{
System.out.println(“CsvFileReader中的错误!!!”;
e、 printStackTrace();
}最后
{
尝试
{
fileReader.close();
}捕获(IOE异常)
{
System.out.println(“关闭文件读取器时出错!!!”;
e、 printStackTrace();
}
}
留学生;
}
测试方法

@Test
    public void ReadCsvFileTest()
    {
        String fileName = "test.csv";
        List<Student> result = new ArrayList<Student>();
        result = CsvFileReader.readCsvFile(fileName);

        Student student1 = null;

        Iterator<Student> it = result.iterator();
        while (it.hasNext())
        {
            Student s = it.next();
            if ("471908US".equals(s.getId()))
            {
                student1 = s;
                break;
            }
        }

        assertTrue(student1 != null);
    }
@测试
public void ReadCsvFileTest()
{
字符串fileName=“test.csv”;
列表结果=新建ArrayList();
结果=CsvFileReader.readCsvFile(文件名);
student1=null;
迭代器it=result.Iterator();
while(it.hasNext())
{
学生s=it.next();
如果(“471908US”.equals(s.getId()))
{
学生1=s;
打破
}
}
assertTrue(student1!=null);
}

考虑到被测方法的当前签名,实现完全覆盖并不容易:只有在try块中抛出异常时,才会执行catch块

解决这个问题的一种方法是:不要传入文件名,而是传入读卡器对象本身。比如:

public static List<Student> readCsvFile(String fileName) {
  return readCsvFile(new BufferedReader(fileName));
}

static List<Student> readCsvFile(BufferedReader reader) { 
  try {
    ...
  } catch( ...
公共静态列表readCsvFile(字符串文件名){
返回readCsvFile(新的BufferedReader(文件名));
}
静态列表readCsvFile(BufferedReader读取器){
试一试{
...
}捕获(。。。
现在,您可以为第二种方法编写几个特定的单元测试。您可以保留只进行“正确”读取的测试;但是您可以添加一个测试,在其中传入一个模拟的reader对象…这只是在某个点上引发一个异常。请注意,我使该新方法仅受包保护-您可能不想使用该“public”;将其私有化将防止其进行单元测试

这将帮助您实现完全覆盖。当然,您还需要至少一个测试来“覆盖”字符串提取方法

一些注意事项:

  • 在重新发明轮子时要小心。已经有许多现有的CSV解析器。请确保:编写一个能够处理所有“正确”输入CSV的正确的CSV解析器要比听起来困难得多。如果这不是为了“学习目的”,我强烈建议不要编写自己的CSV解析器
  • 要注意使这些东西是静态的。正如前面所说的,一个真正的CSV解析器是一件复杂的事情,它值得拥有一个完整的类。所以没有静态的助手方法——一个普通的类,你可以实例化它然后调用它的方法(这也适用于使用依赖项注入,,这将有助于解决您所问的问题…在try块中引发异常)
  • 在代码示例中,您正在捕获异常。不要这样做-尝试准确捕获代码实际生成的异常(可能是IOException)

  • 在这样的情况下,你可能经常考虑向你的类引入额外的依赖关系。下面是一个粗略的例子。为读者创建一个工厂:

    interface BufferedReaderFactory
    {
        public BufferedReader createBufferedReader(String fileName) throws IOException;
    }
    
    然后,您将有一个几乎不需要任何测试的简单实现,例如类似的东西:

    class BufferedReaderFactoryImpl implements BufferedReaderFactory
    {
        @Override
        public BufferedReader createBufferedReader(String fileName) throws IOException
        {
            return new BufferedReader(new FileReader(fileName));
        }
    }
    
    然后,您必须找到一种方法将此依赖项注入到类中。我通常在日常工作中使用,但您可以尝试一些简单的方法,例如使用构造函数注入并使方法非静态。以下是一个示例:

    class CsvFileReader
    {
        private final BufferedReaderFactory factory;
    
        public CsvFileReader(BufferedReaderFactory factory)
        {
            this.factory = factory;
        }
    
        public List<Student> readCsvFile(String fileName)
        {
    
            BufferedReader fileReader = null;
            try
            {
                fileReader = factory.createBufferedReader(fileName);
                ...
            }
            catch(IOException e)
            {
                ...
            }
            finally
            {
                ...
            }
            return new LinkedList<>();
        }
    }
    
    当然,您可以在没有Mockito的情况下通过实现一个测试工厂来实现这一点。但是这更麻烦,尤其是在更复杂的用例中。一旦抛出
    IOException
    ,您将获得JaCoCo提供的适当的覆盖率报告


    还要注意JaCoCo的一个限制,在第节中,有异常的源代码行不显示覆盖率。为什么?

    只有在抛出异常时,才会获得异常块的覆盖率。
    CsvFileReader.readCsvFile(“notexisting.csv”)
    应该输入catchAs Compass建议您在测试执行期间必须在try块内抛出异常。通常我会使用类似Mockito的模拟框架来实现此目的。但在您的情况下,可能传递无效文件名就足够了。
    @RunWith(MockitoJUnitRunner.class)
    public class MyTest
    {
        @Mock
        private BufferedReaderFactory mockFactroy;
    
        @Test
        public void testIOException() throws IOException
        {
            String ivalidFileName = "invalid.txt";
            //throw exception in case that invalid file name is passed to the factory
            Mockito.when(mockFactroy.createBufferedReader(ivalidFileName)).thenThrow(new IOException("Hello!"));
    
            CsvFileReader csvFileReader = new CsvFileReader(mockFactroy);
            //invoke with a factory that throws exceptions
            csvFileReader.readCsvFile(ivalidFileName);
            //...
            //and make a sensible test here, e.g. check that empty list is returned, or proper message is logged, etc.
        }
    }