cho*_*bo2 72 .net asp.net-mvc moq sqlexception
我试图在我的项目中测试一些异常,并且我遇到的一个例外是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()
Run Code Online (Sandbox Code Playgroud)
在尝试模型时发布到第一行
var ex = new Mock<System.Data.SqlClient.SqlException>();
ex.SetupGet(e => e.Message).Returns("Exception message");
Run Code Online (Sandbox Code Playgroud)
Sam*_*ron 77
你可以用反射做这件事,你必须在微软进行更改时维护它,但它确实有效我只是测试它:
public class SqlExceptionCreator
{
private static T Construct<T>(params object[] p)
{
var ctors = typeof(T).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
return (T)ctors.First(ctor => ctor.GetParameters().Length == p.Length).Invoke(p);
}
internal static SqlException NewSqlException(int number = 1)
{
SqlErrorCollection collection = Construct<SqlErrorCollection>();
SqlError error = Construct<SqlError>(number, (byte)2, (byte)3, "server name", "error message", "proc", 100);
typeof(SqlErrorCollection)
.GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(collection, new object[] { error });
return typeof(SqlException)
.GetMethod("CreateException", BindingFlags.NonPublic | BindingFlags.Static,
null,
CallingConventions.ExplicitThis,
new[] { typeof(SqlErrorCollection), typeof(string) },
new ParameterModifier[] { })
.Invoke(null, new object[] { collection, "7.0.0" }) as SqlException;
}
}
Run Code Online (Sandbox Code Playgroud)
这也允许您控制SqlException的数量,这可能很重要.
Dyl*_*tie 61
我有一个解决方案.我不确定这是天才还是疯狂.
以下代码将创建一个新的SqlException:
public SqlException MakeSqlException() {
SqlException exception = null;
try {
SqlConnection conn = new SqlConnection(@"Data Source=.;Database=GUARANTEED_TO_FAIL;Connection Timeout=1");
conn.Open();
} catch(SqlException ex) {
exception = ex;
}
return(exception);
}
Run Code Online (Sandbox Code Playgroud)
你可以这样使用(这个例子是使用Moq)
mockSqlDataStore
.Setup(x => x.ChangePassword(userId, It.IsAny<string>()))
.Throws(MakeSqlException());
Run Code Online (Sandbox Code Playgroud)
这样您就可以在存储库,处理程序和控制器中测试SqlException错误处理.
现在我需要去躺下.
def*_*mer 18
根据具体情况,我通常更喜欢使用GetUninitializedObject来调用ConstructorInfo.您只需要知道它不会调用构造函数 - 来自MSDN备注:"因为对象的新实例初始化为零并且没有运行构造函数,所以该对象可能不代表被视为有效的状态通过那个对象." 但我认为它比依赖某个构造函数的存在要脆弱得多.
[TestMethod]
[ExpectedException(typeof(System.Data.SqlClient.SqlException))]
public void MyTestMethod()
{
throw Instantiate<System.Data.SqlClient.SqlException>();
}
public static T Instantiate<T>() where T : class
{
return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(T)) as T;
}
Run Code Online (Sandbox Code Playgroud)
jjx*_*tra 17
如果您使用新的 Microsoft.Data.SqlClient Nuget 包,则可以使用此帮助器方法:
public static class SqlExceptionCreator
{
public static SqlException Create(int number)
{
Exception? innerEx = null;
var c = typeof(SqlErrorCollection).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
SqlErrorCollection errors = (c[0].Invoke(null) as SqlErrorCollection)!;
var errorList = (errors.GetType().GetField("_errors", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(errors) as List<object>)!;
c = typeof(SqlError).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
var nineC = c.FirstOrDefault(f => f.GetParameters().Length == 9)!;
SqlError sqlError = (nineC.Invoke(new object?[] { number, (byte)0, (byte)0, "", "", "", (int)0, (uint)0, innerEx}) as SqlError)!;
errorList.Add(sqlError);
SqlException ex = (Activator.CreateInstance(typeof(SqlException), BindingFlags.NonPublic | BindingFlags.Instance, null, new object?[] { "test", errors,
innerEx, Guid.NewGuid() }, null) as SqlException)!;
return ex;
}
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*ton 13
编辑 Ouch:我没有意识到SqlException是密封的.我一直在嘲笑DbException,这是一个抽象类.
您无法创建新的SqlException,但您可以模拟SbException派生自的DbException.试试这个:
var ex = new Mock<DbException>();
ex.ExpectGet(e => e.Message, "Exception message");
var conn = new Mock<SqlConnection>();
conn.Expect(c => c.Open()).Throws(ex.Object);
Run Code Online (Sandbox Code Playgroud)
因此,当方法尝试打开连接时,抛出异常.
如果您希望Message在模拟异常上读取除属性之外的任何内容,那么不要忘记Expect(或安装程序,具体取决于您的Moq版本)这些属性上的"get".
由于您使用的是Linq to Sql,以下是使用NUnit和Moq测试您提到的场景的示例.我不知道您的DataContext的确切细节以及您可以使用的内容.根据您的需求进行编辑
您需要使用自定义类包装DataContext,不能使用Moq模拟DataContext.你也不能模拟SqlException,因为它是密封的.您需要使用自己的Exception类包装它.要完成这两件事并不困难.
让我们从创建测试开始:
[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);
}
Run Code Online (Sandbox Code Playgroud)
让我们实现测试,首先让我们使用存储库模式将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);
}
}
Run Code Online (Sandbox Code Playgroud)
接下来像这样创建IDataContextWrapper,你可以查看关于这个主题的博客帖子,我的有点不同:
public interface IDataContextWrapper : IDisposable
{
Table<T> Table<T>() where T : class;
}
Run Code Online (Sandbox Code Playgroud)
接下来创建CustomSqlException类:
public class CustomSqlException : Exception
{
public CustomSqlException()
{
}
public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
{
}
}
Run Code Online (Sandbox Code Playgroud)
这是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
}
Run Code Online (Sandbox Code Playgroud)
不确定这是否有帮助,但似乎对这个人有用(非常聪明)。
try
{
SqlCommand cmd =
new SqlCommand("raiserror('Manual SQL exception', 16, 1)",DBConn);
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
string msg = ex.Message; // msg = "Manual SQL exception"
}
Run Code Online (Sandbox Code Playgroud)
位于:http : //smartypeeps.blogspot.com/2006/06/how-to-throw-sqlexception-in-c.html
| 归档时间: |
|
| 查看次数: |
48251 次 |
| 最近记录: |