116 Stimmen

Wie man eine SqlException auslösen, wenn für Mocking und Unit Testing benötigt?

Ich versuche, einige Ausnahmen in meinem Projekt zu testen und eine der Ausnahmen, die ich abfangen ist SQlException .

Es scheint, dass Sie nicht gehen können new SqlException() so bin ich nicht sicher, wie ich eine Ausnahme vor allem ohne irgendwie Aufruf der Datenbank auslösen kann (und da diese Unit-Tests sind es in der Regel empfohlen, nicht die Datenbank aufrufen, da es langsam ist).

Ich verwende NUnit und Moq, aber ich bin mir nicht sicher, wie man dies vortäuscht.

Als Antwort auf einige der Antworten, die alle auf ADO.NET zu basieren scheinen, beachten Sie, dass ich Linq to Sql verwende. Also ist das Zeug wie hinter den Kulissen.

Weitere Informationen auf Anfrage von @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()

Postet in der ersten Zeile, wenn es versucht, ein Mockup zu erstellen

 var ex = new Mock<System.Data.SqlClient.SqlException>();
 ex.SetupGet(e => e.Message).Returns("Exception message");

2voto

FrenchData Punkte 620

Ich habe bemerkt, dass Ihre Frage schon ein Jahr alt ist, aber für das Protokoll möchte ich eine Lösung hinzufügen, die ich kürzlich mit Microsoft Moles entdeckt habe (Referenzen finden Sie hier Microsoft Maulwürfe )

Sobald Sie den System.Data-Namensraum gemodelt haben, können Sie einfach eine SQL-Ausnahme bei SqlConnection.Open() wie folgt simulieren:

//Create a delegate for the SqlConnection.Open method of all instances
        //that raises an error
        System.Data.SqlClient.Moles.MSqlConnection.AllInstances.Open =
            (a) =>
            {
                SqlException myException = new System.Data.SqlClient.Moles.MSqlException();
                throw myException;
            };

Ich hoffe, dies kann jemandem helfen, der in Zukunft auf diese Frage stößt.

1voto

Grokodile Punkte 3791

(Sry es ist 6 Monate zu spät, hoffen, dass dies nicht als necroposting ich landete hier auf der Suche nach wie man eine SqlCeException von einem Mock werfen).

Wenn Sie nur den Code testen müssen, der die Ausnahme behandelt, wäre eine sehr einfache Abhilfe möglich:

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());

1voto

khebbie Punkte 2462

Auf der Grundlage aller anderen Antworten habe ich die folgende Lösung erstellt:

    [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();
    }

1voto

Rob Punkte 1977

Dieses Thema ist schon sehr alt, und es gibt hier einige gute Antworten. Ich verwende Moq, und ich kann nicht mock up abstrakte Klassen und wirklich wollte nicht, Reflexion zu verwenden, so dass ich meine eigene Exception abgeleitet von DbException gemacht. So:

public class MockDbException : DbException {
  public MockDbException(string message) : base (message) {}
}   

natürlich, wenn Sie InnerException, oder was auch immer hinzufügen müssen, fügen Sie mehr Requisiten, Konstruktoren, etc.

dann in meinem Test:

MyMockDatabase.Setup(q => q.Method()).Throws(new MockDbException(myMessage));

Hoffentlich hilft das jedem, der Moq benutzt. Danke an alle, die hier gepostet haben und mich zu meiner Antwort geführt haben.

1voto

DSoa Punkte 643

Ich war nur mit dem Ansatz von @jjxtra erfolgreich (den ich hochgestuft habe), aber der Code musste geändert werden, da ich System.Data.SqlClient verwende, der keinen 9-Parameter-Konstruktor für SqlError hat, und SqlErrorCollection hat ein Feld namens "errors" (nicht "_errors"), das vom Typ ArrayList (nicht List<object>) ist.

// Montageort: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll

Hier ist der geänderte Code, der bei mir funktioniert:

  public static SqlException CreateSqlException(int number)
  {
    Exception? innerEx = null;
    var c = typeof(SqlErrorCollection).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
    SqlErrorCollection errors = (c[0].Invoke(null) as SqlErrorCollection);
    ArrayList errorList = (ArrayList)errors.GetType().GetField("errors", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(errors);
    c = typeof(SqlError).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
    var theC = c.FirstOrDefault(f => f.GetParameters().Length == 8);
    SqlError sqlError = (theC.Invoke(new object?[] { number, (byte)0, (byte)0, "", "", "", (int)0, (uint)0}) 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;
  }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X