Moq并抛出一个SqlException

我有以下代码来测试,当某个名称传递给我的方法时,它会抛出一个SQLexception(有理由那个,虽然听起来有点奇怪)。

mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny(), "Display Name 2", It.IsAny())).Throws(); 

但是,这不会编译,因为SqlException的构造函数是内部的:

‘System.Data.SqlClient.SqlException’必须是具有公共无参数构造函数的非抽象类型,以便在generics类型或方法’Moq.Language.IThrows.Throws()’中将其用作参数’TException’

现在,我可以更改它以声明它应该抛出Exception ,但这对我不起作用,因为我的方法应该返回一个状态代码,如果它是一个SqlException而另一个是任何其他exception。 这就是我的unit testing正在测试的内容。

有没有办法实现这一点,既没有改变我正在测试的方法的逻辑,或没有测试这种情况?

这应该工作:

 using System.Runtime.Serialization; var exception = FormatterServices.GetUninitializedObject(typeof(SqlException)) as SqlException; mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny(), "Display Name 2", It.IsAny())).Throws(exception); 

但是,使用GetUninitializedObject有这个警告:

因为对象的新实例初始化为零并且没有运行构造函数,所以该对象可能不表示该对象认为有效的状态。

如果这会导致任何问题,你可以使用一些更复杂的reflection魔法创建它,但这种方式可能是最简单的(如果它有效)。

如果需要exception的NumberMessage属性的测试用例,可以使用这样的构建器(使用reflection):

 using System; using System.Data.SqlClient; using System.Reflection; public class SqlExceptionBuilder { private int errorNumber; private string errorMessage; public SqlException Build() { SqlError error = this.CreateError(); SqlErrorCollection errorCollection = this.CreateErrorCollection(error); SqlException exception = this.CreateException(errorCollection); return exception; } public SqlExceptionBuilder WithErrorNumber(int number) { this.errorNumber = number; return this; } public SqlExceptionBuilder WithErrorMessage(string message) { this.errorMessage = message; return this; } private SqlError CreateError() { // Create instance via reflection... var ctors = typeof(SqlError).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance); var firstSqlErrorCtor = ctors.FirstOrDefault( ctor => ctor.GetParameters().Count() == 7); // Need a specific constructor! SqlError error = firstSqlErrorCtor.Invoke( new object[] { this.errorNumber, new byte(), new byte(), string.Empty, string.Empty, string.Empty, new int() }) as SqlError; return error; } private SqlErrorCollection CreateErrorCollection(SqlError error) { // Create instance via reflection... var sqlErrorCollectionCtor = typeof(SqlErrorCollection).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; SqlErrorCollection errorCollection = sqlErrorCollectionCtor.Invoke(new object[] { }) as SqlErrorCollection; // Add error... typeof(SqlErrorCollection).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(errorCollection, new object[] { error }); return errorCollection; } private SqlException CreateException(SqlErrorCollection errorCollection) { // Create instance via reflection... var ctor = typeof(SqlException).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; SqlException sqlException = ctor.Invoke( new object[] { // With message and error collection... this.errorMessage, errorCollection, null, Guid.NewGuid() }) as SqlException; return sqlException; } } 

然后你可以有一个存储库mock(例如)抛出这样的exception:

 using Moq; var sqlException = new SqlExceptionBuilder().WithErrorNumber(50000) .WithErrorMessage("Database exception occured...") .Build(); var repoStub = new Mock>(); // Or whatever... repoStub.Setup(stub => stub.GetById(1)) .Throws(sqlException); 

我刚尝试了这个,它对我有用:

 private static void ThrowSqlException() { using (var cxn = new SqlConnection("Connection Timeout=1")) { cxn.Open(); } } // ... mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny), "Display Name 2", It.IsAny())) .Callback(() => ThrowSqlException());