如何测试调用数据库的方法

时间:2018-01-09 20:54:10

标签: c# database unit-testing mocking

我有几种方法可以连接到数据库,但我无法弄清楚如何为它们编写单元测试。以下是我正在谈论的一个例子。

public static User GetByPendingUserId(int a_PendingUserId)
{
    User l_User = new User();
    SqlConnection l_conn = DbHelp.CreateSqlConnection();
    SqlCommand l_cmd = DbHelp.CreateCommand(l_conn, "User_Get");
    l_cmd.Parameters.AddWithValue("@a_PendingUserId", a_PendingUserId);
    DataTable l_result = new DataTable();
    SqlDataAdapter l_adapter = new SqlDataAdapter(l_cmd);
    l_conn.Open();
    l_adapter.Fill(l_result);
    l_conn.Close();
    l_adapter.Dispose();
    l_cmd.Dispose();
    if (l_result.Rows.Count > 0)
    {
        User.SetMembers(l_result.Rows[0], l_User);
    }
    return l_User;
}

由于我正在编写单元测试而不是集成测试,因此我想测试方法的逻辑而不连接到实际的数据库。我怎么能这样做?

1 个答案:

答案 0 :(得分:3)

假设您要测试依赖于这些方法的代码,您可以通过使用 Repository 模式实现此目的。您将系统的给定部分的数据访问封装到称为存储库的抽象中。因此,在您的情况下,您可能有一个用户存储库,它将包含以下接口和相应的实现。

public interface IUserRepository
{
    User GetByPendingUserId(int a_PendingUserId)
}

请注意GetByPendingUserId不再是静态的。

您现在可以实现此界面。因此,您的实际生产实现可能如下所示:

public class UserRepository : IUserRepository
{
    public User GetByPendingUserId(int a_PendingUserId)
    {
        User l_User = new User();
        SqlConnection l_conn = DbHelp.CreateSqlConnection();
        SqlCommand l_cmd = DbHelp.CreateCommand(l_conn, "User_Get");
        l_cmd.Parameters.AddWithValue("@a_PendingUserId", a_PendingUserId);
        DataTable l_result = new DataTable();
        SqlDataAdapter l_adapter = new SqlDataAdapter(l_cmd);
        l_conn.Open();
        l_adapter.Fill(l_result);
        l_conn.Close();
        l_adapter.Dispose();
        l_cmd.Dispose();
        if (l_result.Rows.Count > 0)
        {
            User.SetMembers(l_result.Rows[0], l_User);
        }
        return l_User;
    }
}

出于测试目的,您现在可以实现另一个版本,返回您喜欢的任何数据以符合您的测试目标。也许它只返回一个new User。它取决于你。关键是你不再依赖于实际的数据库,你可以专注于在单元测试中测试应用程序的逻辑。

public class TestUserRepository : IUserRepository
{
    public User GetByPendingUserId(int a_PendingUserId)
    {
        return new User()
    }
}

一旦你有更多这样的接口,你就可以看一下使用一个模拟框架,它可以让你在测试特定场景时有更多的灵活性。