Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throw a SqlException when needed for mocking and unit testing?

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"); 
like image 416
chobo2 Avatar asked Sep 06 '09 23:09

chobo2


People also ask

Can we throw SQLException?

The following subclasses of SQLException can also be thrown: BatchUpdateException is thrown when an error occurs during a batch update operation. In addition to the information provided by SQLException , BatchUpdateException provides the update counts for all statements that were executed before the error occurred.

Should I mock DB in unit tests?

Unit tests are incredibly important to us as developers because they allow us to demonstrate the correctness of the code we've written. More importantly, unit tests allow us to make updates to our code base with confidence that we haven't broken anything.

Should exceptions be unit tested?

Unit test cases for exceptions should improve the stability and robustness of your application. Unit Test cases can ensure of proper exception handling is implemented.


1 Answers

You can do this with reflection, you will have to maintain it when Microsoft make changes, but it does work I just tested it:

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

This also allows you to control the Number of the SqlException, which can be important.

like image 113
Sam Saffron Avatar answered Sep 17 '22 07:09

Sam Saffron