我试图在我的项目中测试一些异常,其中一个异常是SQlException.

似乎你不能达到new SqlException(),所以我不确定如何抛出异常,尤其是在不调用数据库的情况下(由于这些是单元测试,通常建议不要调用数据库,因为它很慢).

我正在使用NUnit和Moq,但我不确定如何伪造这一点.

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

如@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()

当它try 模拟时将帖子发布到第一行

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

推荐答案

由于您使用的是LINQtoSQL,下面是一个使用NUnit和Moq测试您提到的场景的示例.我不知道你的DataContext的确切细节,也不知道你可以从中获得什么.根据你的需要编辑.

您需要用自定义类包装DataContext,不能用Moq模拟DataContext.您也不能模拟SqlException,因为它是密封的.您需要用自己的异常类来包装它.完成这两件事并不难.

让我们从创建测试开始:

[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);
}

让我们实现测试,首先让我们使用存储库模式包装Linq到Sql调用:

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);
    }
}

接下来像这样创建IDataContextWrapper,你可以查看这个主题的blog post,我的有点不同:

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

接下来创建CustomSqlException类:

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

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

以下是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
}

.net相关问答推荐

如何使用AWS Lambda函数制作网络挂钩?

带有ASP.NET核心的Angular 项目模板.API试验

如何将多个安装程序Bundle 到一个安装程序中?

避免函数和其他对象之间的相互递归的模式?

如何判断属性设置器是否公开

Web API 中基于令牌的身份验证,无需任何用户界面

如何获得友好的操作系统版本名称?

将 BitmapImage 转换为 Bitmap,反之亦然

您可以在 C# 代码中捕获本机异常吗?

我们应该总是在类中包含一个默认构造函数吗?

向 .NET 应用程序添加脚本功能

.NET 中是否有可序列化的通用键/值对类?

在 .NET 中填充整数列表

覆盖 ASP.NET MVC 中的授权属性

等待 Async Void 方法调用以进行单元测试

在 .Net 中调用 Web 服务时绕过无效的 SSL 证书错误

表单不响应 KeyDown 事件

在 .NET 中乘以时间跨度

如何从 webclient 获取状态码?

什么时候使用 Tuple 和 KeyValuePair 比较好?