【问题标题】:Can you explain how the Exception is available in the test case?你能解释一下异常在测试用例中是如何可用的吗?
【发布时间】:2013-10-21 10:20:07
【问题描述】:

有一个关于在 Junits 中检查已处理异常的问题。我似乎在我的代码中做到了这一点。其他人倾向于说这是不可能的,因为该方法没有抛出异常。有人可以解释下面代码中发生的事情吗?

public class DatabaseConnector
{

private DBConnectionInfo dbObject;
private DBQueryStatements dbQueries;

void loadConnectionInfo()
{
    Properties databaseProperties = new Properties();
    try
    {
        databaseProperties.load(getClass().getClassLoader().getResourceAsStream("database.properties"));
        dbObject.setDatabaseURL(databaseProperties.getProperty("jdbc.url"));
        dbObject.setUserName(databaseProperties.getProperty("jdbc.username"));
        dbObject.setPassword(databaseProperties.getProperty("jdbc.password"));
        dbObject.setDriver(databaseProperties.getProperty("jdbc.driver"));
    } catch (IOException e)
    {

        Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
        lgr.log(Level.SEVERE, e.getMessage(), e);
    }

}

public DBConnectionInfo connectionInit()
{

    loadConnectionInfo();

    try
    {
        Class.forName(dbObject.getDriver());
    } catch (Exception e)
    {
        Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
        lgr.log(Level.SEVERE, e.getMessage(), e);
    }

    try
    {
        dbObject.setConnection(DriverManager.getConnection(dbObject.getDatabaseURL(), dbObject.getUserName(),
                dbObject.getPassword()));
    } catch (Exception e)
    {
        Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
        lgr.log(Level.SEVERE, e.getMessage(), e);
    }
    return dbObject;
}
}

以上代码的测试用例。

public class DatabaseConnectorTest
{

DatabaseConnector dbConnector;
DBConnectionInfo dbModelObject;
DBQueryStatements dbQueries;

    @Before
    public void setUp() throws Exception
    {
        MockitoAnnotations.initMocks(this);
        dbModelObject = mock(DBConnectionInfo.class);
        dbQueries = mock(DBQueryStatements.class);    
        dbConnector = new DatabaseConnector(dbModelObject,dbQueries);
    }

@Test
public void testDriverFailure()
{
    when(dbModelObject.getDriver()).thenReturn("driver");
    when(dbModelObject.getDatabaseURL()).thenReturn("jdbc:postgresql://127.0.0.1:5432/testdb");
    when(dbModelObject.getUserName()).thenReturn("postgres");
    when(dbModelObject.getPassword()).thenReturn("postgres");

    try
    {
        dbConnector.connectionInit();
    } catch (Exception e)
    {
        assertTrue(e instanceof ClassNotFoundException);
    }

    verify(dbModelObject).getDriver();
}

@Test
public void testConnectionFailure()
{
    when(dbModelObject.getDriver()).thenReturn("org.postgresql.Driver");
    when(dbModelObject.getDatabaseURL()).thenReturn("jdbc:postgresql://127.0.0.1:5432/testdb");
    when(dbModelObject.getUserName()).thenReturn("uname");
    when(dbModelObject.getPassword()).thenReturn("uname");
    try
    {
        dbConnector.connectionInit();
    } catch (Exception e)
    {
        assertTrue(e instanceof SQLException);
    }

    verify(dbModelObject).getDriver();
    verify(dbModelObject).getDatabaseURL();
    verify(dbModelObject).getUserName();
    verify(dbModelObject).getPassword();
}
}

【问题讨论】:

  • 您可以删除“MockitoAnnotations.initMocks(this);”行,因为您没有使用注释来启动模拟。

标签: java unit-testing exception-handling junit


【解决方案1】:

你可以简单地使用@Test注解

@Test(expected=RuntimeException.class)

另一种解决方案是,当您期望出现异常时,您应该让测试失败

@Test
public void testConnectionFailure()
{
    ...
    try
    {
        dbConnector.connectionInit();
        fail("an exception should be thrown...")
    } catch (Exception e)
    {
        assertTrue(e instanceof SQLException);
    }
    ...
}  

更新 #1:

我认为你的代码和测试用例不是很好,因为在你的代码中你捕获了所有“好”的异常!但他们告诉你出了什么问题。

所以让您的代码抛出这些异常。

但另一方面是:为什么要为标准 javajava.sql 功能(ClassLoading、DriverManager)编写测试用例?

更新 #2:

我会用你的例子来解释,因为我不是英语本地人。 ;)

您的代码:

try
{
        Class.forName(dbObject.getDriver());  
} catch (Exception e)
{
        Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
        lgr.log(Level.SEVERE, e.getMessage(), e);
}

您的代码:

try
{
        Do something from java standard. //Class.forName(dbObject.getDriver());  
} if an exception occures, go in this block //catch (Exception e) 
{
        Just print out the exception. 
        If someone knowns about your application he'll take a look in the log. 
        If not, your exception is lost, after leaving this block.
        And I think here is your problem!
        Do not catch any exceptions in a so low level of your application.
}

你的测试用例:

@Test
public void testDriverFailure()
{
    ....
    try
    {
        dbConnector.connectionInit();
    } catch (Exception e)
    {
        assertTrue(e instanceof ClassNotFoundException);
    }
}

你的测试用例:

@Test
public void testDriverFailure()
{
    ....
    try
    {
        try to init your dbConnector. 
    } Catch exceptions (
          They never thrown, because you already catched them in the method connectionInit().
          And here right now, you know, why its a bad idea 
          to catch exceptions and place them into logfiles (except in the very high level of your application)!
      )
    {
        Now Check, that the Java-VM ClassLoader (Not your code!!!) will throw an ClassNotFoundException. 
        Why you not trusting the jvm developers? ;)
    }
}

【讨论】:

  • 您能否详细说明。 java sql特性不用写测试用例吗?
  • 再次更新。 ;) 而且我认为,不,您不应该为第三方库编写测试用例。除非您不信任它们,或者希望保证第三方库的行为在版本更改后保持不变。
【解决方案2】:

您在代码中捕获异常并将某些内容写入日志。因此,测试看不到异常,您无法测试它是否被抛出。但是您可以测试您是否记录了某些内容。另一种方法是测试您的代码是否不会引发异常并返回 null。

【讨论】:

  • 上述测试用例运行成功。我没有从测试方法中抛出异常。但它似乎在我不明白的测试用例中可用。
  • 对不起,我的错。 “它似乎在测试用例中可用”是什么意思?
  • 测试用例中存在异常。我正在测试用例中处理它。检查我测试异常类型的 catch 块。
  • 我认为你的 catch 块没有被执行,因为没有抛出异常。您可以随时将 try { } catch (Exception e) { } 添加到您的代码中。这没有任何意义。
  • 您正在处理的“异常”是什么?
【解决方案3】:

connectionInit () 方法,正如它目前所写的那样,不会引发任何异常。在您的两个测试用例中,您应该检查预期的失败(根据我对您的代码的理解),但是如果没有发生失败,您不会调用 fail () JUnit 方法,所以您的印象是您的测试用例两者都通过,而他们都应该失败。正如 Mirko 所说,您应该在调用 connectionInit () 之后将代码更改为调用 fail ()

【讨论】:

    猜你喜欢
    • 2013-06-24
    • 2017-03-19
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多