Puisque vous utilisez Linq to Sql, voici un exemple de test du scénario que vous avez mentionné en utilisant NUnit et Moq. Je ne connais pas les détails exacts de votre DataContext et de ce que vous y avez à disposition. Modifiez pour vos besoins.
Vous devrez envelopper le DataContext avec une classe personnalisée, vous ne pouvez pas simuler le DataContext avec Moq. Vous ne pouvez pas non plus simuler SqlException, car elle est scellée. Vous devrez l'envelopper avec votre propre classe d'exception. Il n'est pas très difficile d'accomplir ces deux choses.
Commençons par créer notre 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);
}
Mettons en œuvre le test, d'abord nous enveloppons nos appels Linq to Sql en utilisant le modèle de dépôt :
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);
}
}
Ensuite, créez l'IDataContextWrapper comme suit, vous pouvez voir ceci article de blog sur le sujet, le mien diffère un peu :
public interface IDataContextWrapper : IDisposable
{
Table<T> Table<T>() where T : class;
}
Créez ensuite la classe CustomSqlException :
public class CustomSqlException : Exception
{
public CustomSqlException()
{
}
public CustomSqlException(string message, SqlException innerException) : base(message, innerException)
{
}
}
Voici un exemple d'implémentation de l'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
}
1 votes
Vous avez raison. J'ai mis à jour ma réponse, mais elle n'est probablement pas très utile maintenant. DbException est probablement la meilleure exception à attraper, alors pensez-y.
0 votes
Les réponses qui fonctionnent réellement produisent une variété de messages d'exception. Il peut être utile de définir exactement le type dont vous avez besoin. Par exemple : "J'ai besoin d'une SqlException qui contient le numéro d'exception 18487, indiquant que le mot de passe spécifié a expiré." Il semble qu'une telle solution soit plus appropriée pour les tests unitaires.