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(
Depending on the situation, I usually prefer GetUninitializedObject to invoking a ConstructorInfo. You just have to be aware that it doesn't call the constructor - from the MSDN Remarks: "Because the new instance of the object is initialized to zero and no constructors are run, the object might not represent a state that is regarded as valid by that object." But I'd say it's less brittle than relying on the existence of a certain constructor.
[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;
}
(Sry it's 6 months late, hope this won't be considered necroposting I landed here looking for how to throw a SqlCeException from a mock).
If you just need to test the code that handles the exception an ultra simple workaround would be:
public void MyDataMethod(){
try
{
myDataContext.SubmitChanges();
}
catch(Exception ex)
{
if(ex is SqlCeException || ex is TestThrowableSqlCeException)
{
// handle ex
}
else
{
throw;
}
}
}
public class TestThrowableSqlCeException{
public TestThrowableSqlCeException(string message){}
// mimic whatever properties you needed from the SqlException:
}
var repo = new Rhino.Mocks.MockReposity();
mockDataContext = repo.StrictMock<IDecoupleDataContext>();
Expect.Call(mockDataContext.SubmitChanges).Throw(new TestThrowableSqlCeException());
Theese solutions feel bloated.
The ctor is internal, yes.
(Without using reflection, the easiest way to just genuinely create this exception....
instance.Setup(x => x.MyMethod())
.Callback(() => new SqlConnection("Server=pleasethrow;Database=anexception;Connection Timeout=1").Open());
Perphaps there's another method that doesn't require the timeout of 1 second to throw.
You could use reflection to create SqlException object in the test:
ConstructorInfo errorsCi = typeof(SqlErrorCollection).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[]{}, null);
var errors = errorsCi.Invoke(null);
ConstructorInfo ci = typeof(SqlException).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(SqlErrorCollection) }, null);
var sqlException = (SqlException)ci.Invoke(new object[] { "Exception message", errors });
Since you are using Linq to Sql, here is a sample of testing the scenario you mentioned using NUnit and Moq. I don't know the exact details of your DataContext and what you have available in it. Edit for your needs.
You will need to wrap the DataContext with a custom class, you cannot Mock the DataContext with Moq. You cannot mock SqlException either, because it is sealed. You will need to wrap it with your own Exception class. It is not to difficult to accomplish these two things.
Let's start by creating our test:
[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);
}
Let's implement the test, first let's wrap our Linq to Sql calls using the repository pattern:
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);
}
}
Next create the IDataContextWrapper like so, you can view this blog post on the subject, mine differs a little bit:
public interface IDataContextWrapper : IDisposable
{
Table<T> Table<T>() where T : class;
}
Next create the CustomSqlException class:
public class CustomSqlException : Exception
{
public CustomSqlException()
{
}
public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
{
}
}
Here's a sample implementation of the 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
}
Based on all the other answers I created the following solution:
[Test]
public void Methodundertest_ExceptionFromDatabase_Logs()
{
_mock
.Setup(x => x.MockedMethod(It.IsAny<int>(), It.IsAny<string>()))
.Callback(ThrowSqlException);
_service.Process(_batchSize, string.Empty, string.Empty);
_loggermock.Verify(x => x.Error(It.IsAny<string>(), It.IsAny<SqlException>()));
}
private static void ThrowSqlException()
{
var bogusConn =
new SqlConnection(
"Data Source=localhost;Initial Catalog = myDataBase;User Id = myUsername;Password = myPassword;Connection Timeout = 1");
bogusConn.Open();
}