chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
In several of my unit tests, I need to mock the behavior of a certain method to simulate a foreign key constraint violation in the database. In order to simulate that, I need it the method to throw a SqlException with specific error number and message (that contains exactly which FK column was violated), so that I can see it is handled correctly according to the column name. I am using the following code:

var fakeSqlException = Isolate.Fake.Instance<SqlException>();
Isolate.WhenCalled(() => fakeSqlException.Number).WillReturn(547);
Isolate.WhenCalled(() => fakeSqlException.Message).WillReturn("FK Violation on column CustomerID");


But unfortunately, a TypeMockException is thrown on the last line:

*** No method calls found in recording block. Please check:
 * Are you trying to fake a field instead of a property?
 * Are you are trying to fake an unsupported mscorlib type? See supported types here: https://www.typemock.com/mscorlib-types


The answer to all these questions is no. I do understand that SqlException.Message is a property that is defined in the mscorlib type System.Exception and is never overridden in non-mscorlib types in its way down to SqlException. But still, I am mocking a non-mscorlib type. Is this the reason for the TypeMockException? If so, how would you suggest I test this scenario?
asked by allon.guralnek (10.6k points)

2 Answers

0 votes
Hi Allon,

First you are correct about the reason for the exception.
the Message property is implemented inside mscorlib and that's why the Isolator throws the exception.

As a work around you can use reflection to create a fake SqlExcepion instance.
Here is an example:

// test helper method - using reflection to creates a faked SqlException instance.
private SqlException GetFakeException()
{
    Type sqlExceptionType = typeof (SqlException);

    var types = new Type[] {typeof (string), typeof (SqlErrorCollection)};
    ConstructorInfo constructorInfo = sqlExceptionType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);
    var fakeSqlErrorCollection = Isolate.Fake.Instance<SqlErrorCollection>();
    SqlException fakeSqlException = constructorInfo.Invoke(new object[] {"FK Violation on column CustomerID", fakeSqlErrorCollection}) as SqlException;
    
    Isolate.WhenCalled(() => fakeSqlException.Number).WillReturn(547);
    
    return fakeSqlException;
}


[Test]
public void Test()
{
    SqlException fakeException = GetFakeException();
    
    Foo foo = new Foo();
    Isolate.WhenCalled(() => foo.ThrowingMethod()).WillThrow(fakeException);

    try
    {
        foo.ThrowingMethod();
        Assert.Fail("Should have throw an exception");
    }
    catch (SqlException e)
    {
        Assert.AreEqual(e.Message, "FK Violation on column CustomerID");
        Assert.AreEqual(547, e.Number);
    }
}


Things to note here:
:arrow: I used the ability of the Isolator to change the behavior of non faked instances in the line Isolate.WhenCalled(() => fakeSqlException.Number).WillReturn(547);
:arrow: For clarity I used two Assert statements, the good practice says that a test method should have one Assert. I would advise dividing the test into two tests.
answered by ohad (35.5k points)
0 votes
Thanks, this is a good solution, and so simple. I don't know how I didn't think of it. I guess when you get used to the TypeMock hammer, everything looks like a mockable nail!
answered by allon.guralnek (10.6k points)
...