Je pose cette question à nouveau à la demande du distingué M. John Skeet, qui m’a suggéré d’élaborer un programme de test simple qui isole et démontre le problème que je rencontre et rediffuse la question. Cette question est née de celle-ci , alors pardonnez-moi si cela vous semble très familier. Vous pouvez potentiellement obtenir des détails supplémentaires sur cette question à partir de celle-là.
Le problème que je rencontre concerne Assert.Throws
from NUnit 2.5.9. À l’occasion, il ne parviendra pas à intercepter les exceptions lancées dans la méthode invoquée par TestDelegate. J’ai épinglé ce comportement d’une manière reproductible dans le code ci-dessous. (Bien que cela puisse certes être un cas de Fails On My Machine ™.
Pour reproduire l’erreur, j’ai créé une solution avec deux projets DLL C #:
SqlCommand
, renseigner ses parameters et invoquer ExecuteScalar
dessus. Ce projet ne comprend aucune autre référence. Lorsque j’effectue les tests dans le débogueur, j’observe les éléments suivants:
Assert.Throws
appelle correctement la méthode d’extension ExecuteScalar
. ExecuteScalar
teste ses parameters pour les valeurs NULL. throw new ArgumentNullException(...)
. throw
, le contrôle de l’application n’est pas immédiatement transféré vers Assert.Throws
. Au lieu de cela, il continue sur la ligne suivante dans ExecuteScalar
. Le code source qui isole ce comportement est donné ci-dessous.
LA METHODE D’EXTENSION
namespace NUnit_Anomaly { using System; using System.Data; using System.Data.SqlClient; public static class Class1 { public static T ExecuteScalar(this SqlConnection connection, ssortingng sql) { if (connection == null) { throw new ArgumentNullException("connection"); } if (sql == null) { throw new ArgumentNullException("sql"); } using (var command = connection.CreateCommand()) { command.CommandType = CommandType.Text; command.CommandText = sql; return (T)command.ExecuteScalar(); } } } }
LES CAS D’ESSAI
namespace NUnit_Tests { using System; using System.Data.SqlClient; using System.Diagnostics; using NUnit.Framework; using NUnit_Anomaly; [TestFixture] public class NUnitAnomalyTest { [Test] public void ExecuteDataSetThrowsForNullConnection() { Assert.Throws(() => ((SqlConnection)null).ExecuteScalar(null)); } [Test] public void ExecuteDataSetThrowsForNullSql() { const ssortingng server = "MY-LOCAL-SQL-SERVER"; const ssortingng instance = "staging"; ssortingng connectionSsortingng = Ssortingng.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;", server, instance); using (var connection = new SqlConnection(connectionSsortingng)) { Assert.Throws(() => connection.ExecuteScalar(null)); } } } }
L’effet net est que les tests échouent alors qu’ils ne le devraient pas. Assert.Throws
je Assert.Throws
, Assert.Throws
devrait capturer mon exception et le test devrait réussir.
METTRE À JOUR
J’ai suivi les conseils de Hans et vérifié la boîte de dialog Exceptions. Je ne cassais pas sur les exceptions jetées , mais je cassais sur les exceptions utilisateur non gérées . Apparemment, c’est la raison pour laquelle le débogueur s’est introduit dans l’IDE lorsque l’exception est levée. En décochant la case, le problème a été résolu et Assert.Throws
a relevé. Cependant, si je ne l’ai pas déjà fait, je ne peux pas appuyer simplement sur F5 pour continuer l’exécution, NullReferenceException
l’exception deviendra une exception NullReferenceException
.
Alors maintenant, la question est la suivante: puis-je configurer des interruptions d’exception pour chaque projet? Je veux seulement faire cela quand je teste, mais pas en général.
En fait, Assert.Throws
intercepte votre exception. Toutefois, Visual Studio s’arrête quand même à la première exception. Vous pouvez vérifier cela en appuyant simplement sur F5; Visual Studio sera heureux de continuer à exécuter.
Comme l’assistant d’exception vous l’indique, l’exception n’a pas été gérée par le code utilisateur . Nous soaps donc que Visual Studio ne considère pas NUnit comme un code utilisateur pour une raison quelconque.
Visual Studio vous le dit en clair, si vous savez où regarder:
Il existe également des preuves de ce fait dans la trace de la stack:
Solution 1 : utilisez une version de débogage de NUnit avec des symboles de débogage. Cela obligera Visual Studio à considérer NUnit en tant que code utilisateur et cessera donc de traiter vos exceptions comme “non gérées par le code utilisateur”. Ce n’est pas anodin, mais pourrait fonctionner mieux à long terme.
Solution 2 : désactivez la case à cocher “Activer uniquement mon code” dans les parameters de débogage de Visual Studio:
PS Je n’envisage pas de contournement pour éviter l’utilisation de Assert.Throws
complètement, mais il existe bien sûr des moyens de le faire.