Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq and throwing a SqlException

I have the following code to test that when a certain name is passed to my method, it throws a SQL exception (there is reason to that one, although it sounds a little odd).

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

However, this won't compile because SqlException's constructor is internal:

'System.Data.SqlClient.SqlException' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TException' in the generic type or method 'Moq.Language.IThrows.Throws()'

Now, I could change this to state that it should throw Exception, but that wouldn't work for me, because my method should return one status code if it is a SqlException and another if it is any other exception. That's what my unit test is testing.

Is there any way to achieve this without either changing the logic of the method I'm testing, or not testing this scenario?

like image 994
Fiona - myaccessible.website Avatar asked Aug 15 '12 20:08

Fiona - myaccessible.website


People also ask

What can be mocked with MOQ?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation.

How do you throw an exception in SQL?

If you must have your own message, you can create your own exception class, then assign the SqlException to the InnerException property. Or throw one of the other exceptions and do the same thing (the assign part).

What is SQL exception?

An exception that provides information on a database access error or other errors. Each SQLException provides several kinds of information: a string describing the error. This is used as the Java Exception message, available via the method getMesasge .


1 Answers

If you need test cases for the Number or Message properties of the exception, you could use a builder (which uses reflection) like this:

using System; using System.Data.SqlClient; using System.Linq; 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;     } } 

Then you could have a repository mock (for instance) throw an exception like this (this example uses the Moq library):

using Moq;  var sqlException =      new SqlExceptionBuilder().WithErrorNumber(50000)         .WithErrorMessage("Database exception occured...")         .Build(); var repoStub = new Mock<IRepository<Product>>(); // Or whatever... repoStub.Setup(stub => stub.GetById(1))     .Throws(sqlException); 
like image 125
Aage Avatar answered Sep 21 '22 09:09

Aage