如何需要的嘲笑和单元测试时,抛出SQLException?抛出、单元测试、SQLException

2023-09-02 01:56:59 作者:冷月长空

我想测试一些例外情况在我的项目,我抓到一个例外是 SQLEXCEPTION

看来你不能去新的SQLException(),所以我不知道我怎么能特别是抛出一个异常,而不以某种方式调用数据库(和因为这些是单元测试它通常建议不要调用数据库,因为它是慢)。

我使用NUnit和起订量,但我不知道如何捏造这一点。

在回答了一些,似乎所有的答案是基于ADO.NET,注意,我使用LINQ to SQL。所以,这些东西就像是在幕后。

更多信息所要求的@MattHamilton:

System.ArgumentException:类型嘲笑必须是一个接口或抽象或不密封类。   在Moq.Mock`1.CheckParameters()   在Moq.Mock`1..ctor(MockBehavior行为,对象[]参数)   在Moq.Mock`1..ctor(MockBehavior行为)   在Moq.Mock`1..ctor()

帖子以第一线当它试图样机

  VAR EX =新的模拟< System.Data.SqlClient.SqlException>();
 ex.SetupGet(E => e.Message).Returns(异常信息);
 

解决方案

由于您使用LINQ to SQL中,这里是测试你提到的使用NUnit和起订量的情况下的一个样本。我不知道你的DataContext和你所拥有的在其提供的具体细节。编辑您的需要。

2019数理化 第二单元测试卷 打包下载 不要错过

您需要包裹的DataContext使用自定义类,你不能嘲笑的DataContext以起订量。你不能模拟SQLEXCEPTION任的,因为它是密封的。你需要用自己的Exception类包装它。它不是很难完成这两件事情。

让我们开始创建我们的测试:

  [测试]
公共无效FindBy_When_something_goes_wrong_Should_handle_the_CustomSqlException()
{
    VAR mockDataContextWrapper =新的模拟< IDataContextWrapper>();
    mockDataContextWrapper.Setup(X => x.Table<使用者>())。抛出< CustomSqlException>();

    IUserResository userRespoistory =新UserRepository(mockDataContextWrapper.Object);
    //现在,因为我们已经嘲笑一切,我们正在使用依赖注入。
    //,而不是让用户在FindBy被调用时,我们会得到一个CustomSqlException
    //现在,FindBy内,包装一个尝试捕捉内部调用DataContextWrapper
    //和处理异常,然后测试你处理它,就像嘲笑一个记录器,然后将它传递到存储库和验证的LogMessage被称为
    用户用户= userRepository.FindBy(1);
}
 

让我们实现了测试,首先让我们来包装我们的LINQ到SQL调用使用存储库模式:

 公共接口IUserRepository
{
    用户FindBy(中间体ID);
}

公共类UserRepository:IUserRepository
{
    公共IDataContextWrapper DataContextWrapper {获得;保护套; }

    公共UserRepository(IDataContextWrapper dataContextWrapper)
    {
        DataContextWrapper = dataContextWrapper;
    }

    公众用户FindBy(INT ID)
    {
        返回DataContextWrapper.Table<使用者>()的SingleOrDefault(U => u.UserID == ID)。
    }
}
 

接下来创建IDataContextWrapper像这样,你可以查看此博客文章关于这个问题,我的不同,一点点:

  public接口IDataContextWrapper:IDisposable接口
{
    表< T>表< T>()其中T:类;
}
 

接下来创建CustomSqlException类:

 公共类CustomSqlException:异常
{
 公共CustomSqlException()
 {
 }

 公共CustomSqlException(字符串消息,SQLEXCEPTION的InnerException):基地(消息的InnerException)
 {
 }
}
 

下面是IDataContextWrapper的样本实现:

 公共类DataContextWrapper< T> :IDataContextWrapper其中T:DataContext的,新的()
{
 私人只读牛逼_db;

 公共DataContextWrapper()
 {
        VAR T = typeof运算(T);
     _db =(T)Activator.CreateInstance(T);
 }

 公共DataContextWrapper(字符串的connectionString)
 {
     VAR T = typeof运算(T);
     _db =(T)Activator.CreateInstance(T,的connectionString);
 }

 公共表<表名>表<表名>(),其中表名:类
 {
        尝试
        {
            返程(表<表名>)_db.GetTable(typeof运算(表名));
        }
        赶上(SqlException异常)
        {
            //裹SQLException的与我们的自定义的
            抛出新CustomSqlException(哎呀......除外);
        }
 }

 // IDispoable会员
}
 

I am trying to test some exceptions in my project and one of the Exceptions I catch is SQlException.

It seems that you can't go new SqlException() so I am not sure how I can throw an exception especially without somehow calling the database (and since these are unit tests it is usually advised not to call the database since it is slow).

I am using NUnit and Moq, but I am not sure how to fake this.

Responding to some of the answers that seem to all be based on ADO.NET, note that I am using Linq to Sql. So that stuff is like behind the scenes.

More info as requested by @MattHamilton:

System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class.       
  at Moq.Mock`1.CheckParameters()
  at Moq.Mock`1..ctor(MockBehavior behavior, Object[] args)
  at Moq.Mock`1..ctor(MockBehavior behavior)
  at Moq.Mock`1..ctor()

Posts to the first line when it tries to mockup

 var ex = new Mock<System.Data.SqlClient.SqlException>();
 ex.SetupGet(e => e.Message).Returns("Exception message");

解决方案

Since you are using Linq to Sql, here is a sample of testing the scenario you mentioned using NUnit and Moq. I don't know the exact details of your DataContext and what you have available in it. Edit for your needs.

You will need to wrap the DataContext with a custom class, you cannot Mock the DataContext with Moq. You cannot mock SqlException either, because it is sealed. You will need to wrap it with your own Exception class. It is not to difficult to accomplish these two things.

Let's start by creating our test:

[Test]
public void FindBy_When_something_goes_wrong_Should_handle_the_CustomSqlException()
{
    var mockDataContextWrapper = new Mock<IDataContextWrapper>();
    mockDataContextWrapper.Setup(x => x.Table<User>()).Throws<CustomSqlException>();

    IUserResository userRespoistory = new UserRepository(mockDataContextWrapper.Object);
    // Now, because we have mocked everything and we are using dependency injection.
    // When FindBy is called, instead of getting a user, we will get a CustomSqlException
    // Now, inside of FindBy, wrap the call to the DataContextWrapper inside a try catch
    // and handle the exception, then test that you handled it, like mocking a logger, then passing it into the repository and verifying that logMessage was called
    User user = userRepository.FindBy(1);
}

Let's implement the test, first let's wrap our Linq to Sql calls using the repository pattern:

public interface IUserRepository
{
    User FindBy(int id);
}

public class UserRepository : IUserRepository
{
    public IDataContextWrapper DataContextWrapper { get; protected set; }

    public UserRepository(IDataContextWrapper dataContextWrapper)
    {
        DataContextWrapper = dataContextWrapper;
    }

    public User FindBy(int id)
    {
        return DataContextWrapper.Table<User>().SingleOrDefault(u => u.UserID == id);
    }
}

Next create the IDataContextWrapper like so, you can view this blog post on the subject, mine differs a little bit:

public interface IDataContextWrapper : IDisposable
{
    Table<T> Table<T>() where T : class;
}

Next create the CustomSqlException class:

public class CustomSqlException : Exception
{
 public CustomSqlException()
 {
 }

 public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
 {
 }
}

Here's a sample implementation of the IDataContextWrapper:

public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
{
 private readonly T _db;

 public DataContextWrapper()
 {
        var t = typeof(T);
     _db = (T)Activator.CreateInstance(t);
 }

 public DataContextWrapper(string connectionString)
 {
     var t = typeof(T);
     _db = (T)Activator.CreateInstance(t, connectionString);
 }

 public Table<TableName> Table<TableName>() where TableName : class
 {
        try
        {
            return (Table<TableName>) _db.GetTable(typeof (TableName));
        }
        catch (SqlException exception)
        {
            // Wrap the SqlException with our custom one
            throw new CustomSqlException("Ooops...", exception);
        }
 }

 // IDispoable Members
}