【问题标题】:Junit testing using mockobjects使用模拟对象进行 Junit 测试
【发布时间】:2017-04-13 21:16:39
【问题描述】:

我正在尝试在我的测试失败的第一种情况下编写一些测试,而我知道我的代码有效:

import org.junit.*;
import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;

public class TestGetConnection {
@Test
    public void getConnection() throws SQLException{
    GetConnection getCon = new GetConnection();
    Connection con = getCon.getConnection();
    assertEquals("com.mysql.cj.jdbc.ConnectionImpl@3aa9e816",con.toString());

}
}

这是 GetConnection 类:

package BE.Intec.Daniel.BabySteps;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Scanner;

public class GetConnection {
    private String url2 = "jdbc:mysql://";
    private String url;
    private String user;
    private String timezone = "?useUnicode=true&use  JDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=CET";
    private String password;
    private Scanner input = new Scanner(System.in);

public GetConnection() {
    System.out.println("Geef het adres zonder http:// of www. van de database in aub.");
    url2 += input.nextLine();
    url = url2 + timezone;
    System.out.println("Geef de username in aub.");
    user = input.nextLine();
    System.out.println("Geef het paswoord in aub.");
    password = input.nextLine();

}

public String setUrl(String dbName) {
    url2 += dbName;
    return url = url2 + timezone;
}

public java.sql.Connection getConnection() throws SQLException {
    return DriverManager.getConnection(url, user, password);
    }
}

在第二个测试中,我首先使用模拟对象来获取连接,但不知何故,在尝试创建数据库之前,之前并没有被执行。

package BE.Intec.Daniel.BabySteps;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;

public class TestCreateDatabase {
    private Connection con;
    @Before
    public void init() throws SQLException{
        GetConnection getcon = EasyMock.createMock(GetConnection.class);
        con = getcon.getConnection();
    }

    @Test
    public void createDatabase(){   
        CreateDataBase newDb = new CreateDataBase(con); 
        String result = newDb.createDataBase();
        assertEquals("Uw databse werd succesvol gecreëerd",result);
        }
   }

这里是 CreateDatabase 类:

package BE.Intec.Daniel.BabySteps;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Scanner;
import com.mysql.cj.api.jdbc.Statement;

public class CreateDataBase {
private Connection con;
private java.sql.Statement stat;
private String databaseName;

public CreateDataBase(Connection con) {
    this.con = con;
    createDataBase();
}

public String createDataBase() {
    Scanner in = new Scanner(System.in);
    System.out.println("Hoe moet uw database noemen?");
    databaseName = in.nextLine();
    String succes = "";
    try {
        stat = con.createStatement();
        String statement = "CREATE DATABASE IF NOT EXISTS " + databaseName;
        stat.executeUpdate(statement);
        succes ="Uw databse werd succesvol gecreëerd";
    } catch (SQLException e) {
        System.out.println("Er ging iets fout");
        e.printStackTrace();
    }
    return succes;
}

public String getDatabaseName() {
    return databaseName;
}

}

知道为什么我的测试失败了吗? 任何帮助将不胜感激 别介意我的英语,我是比利时人,所以不是本地人。

【问题讨论】:

    标签: java database junit mocking easymock


    【解决方案1】:

    第一个测试是技术测试。您要检查驱动程序是否正确配置。

    您应该将 scanner.nextLine() 返回的字符串值与值(网址、用户名、密码)存根,以便用于您的测试。
    此外,您不应该在assertEquals() 方法中检查"com.mysql.cj.jdbc.ConnectionImpl@3aa9e816"。依靠 Object 类的默认 toString() 方法来断言结果是一个坏主意,因为它在其表示中包含对象的哈希码(@... 部分),这不是比较内容的正确方法。
    这应该足够了:

    Assert.assertTrue(con.toString().contains("com.mysql.cj.jdbc.ConnectionImpl"));
    

    这是更新的测试方法:

    @Test
    public void getConnection() throws SQLException {
        String input = "urlToTest\nuser\nvalue";
        InputStream in = new ByteArrayInputStream(input.getBytes());
        System.setIn(in);
        GetConnection getCon = new GetConnection();
        Connection con = getCon.getConnection();
        Assert.assertTrue(con.toString().contains("com.mysql.cj.jdbc.ConnectionImpl"));
    }
    

    对于第二个测试,您应该更喜欢 Mockito 而不是 EasyMock,因为它更容易、更有效、更灵活、更强大。 此外,使用的测试逻辑不正确。
    在这里你模拟了GetConnection 对象,但你没有指定在调用方法时模拟对象应该做什么:

    @Before
    public void init() throws SQLException{
        GetConnection getcon = EasyMock.createMock(GetConnection.class);
        con = getcon.getConnection();
    }
    

    无论如何,在此模拟可能不是最佳选择。
    CreateDataBase 类执行数据库创建。
    如果你想测试它,你应该通过集成来测试它(即使用一个真实的数据库。为什么不使用内存数据库)而不是使用模拟。

    【讨论】:

    • 谢谢大卫,这很有帮助。我应该提到这是一个学校作业,我们必须编写一个程序来管理公司的行政管理。 Easymock 是他们在课程中用作示例的,这就是我使用它的原因。我运行了我的代码,所以我知道数据库创建工作正常,但我必须为它编写一个测试。我们应该尝试以大约 95% 的测试覆盖率为目标,但我总是发现很难为 void 方法编写测试
    • 第一次测试。为什么是输入流?不会:@Test public void getConnection() throws SQLException { GetConnection getCon = new GetConnection();连接 con = getCon.getConnection(); Assert.assertTrue(con.toString().contains("com.mysql.cj.jdbc.ConnectionImpl")); } 够了吗?
    • 不客气。不幸的是,在学校,我们并不总是研究要使用的东西......回答你的问题:因为在GetConnection() 构造函数中,你有Scanner 调用:input.nextLine();。如果不为输入模拟数据,输入和测试将永远等待输入。
    猜你喜欢
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多