J'ai préparé des tests automatiques avec le framework de test Visual Studio Team Edition. Je veux que l'un des tests se connecte à la base de données en suivant la procédure normale dans le programme:
string r_providerName = ConfigurationManager.ConnectionStrings["main_db"].ProviderName;
Mais je reçois une exception dans cette ligne. Je suppose que cela se produit parce que le ConfigurationManager est un singleton. Comment pouvez-vous contourner le problème singleton avec des tests unitaires?
Merci pour les réponses. Tous ont été très instructifs.
Jetez un œil au blog de Google Testing :
Et aussi:
Enfin, Misko Hevery a écrit un guide sur son blog: Writing Testable Code .
Vous pouvez utiliser l'injection de dépendance constructeur. Exemple:
public class SingletonDependedClass
{
private string _ProviderName;
public SingletonDependedClass()
: this(ConfigurationManager.ConnectionStrings["main_db"].ProviderName)
{
}
public SingletonDependedClass(string providerName)
{
_ProviderName = providerName;
}
}
Cela vous permet de passer la chaîne de connexion directement à l'objet pendant le test.
De plus, si vous utilisez le framework de test Visual Studio Team Edition, vous pouvez rendre le constructeur avec paramètre privé et tester la classe via l'accesseur.
En fait, je résous ce genre de problèmes avec la moquerie. Exemple:
Vous avez une classe qui dépend de singleton:
public class Singleton
{
public virtual string SomeProperty { get; set; }
private static Singleton _Instance;
public static Singleton Insatnce
{
get
{
if (_Instance == null)
{
_Instance = new Singleton();
}
return _Instance;
}
}
protected Singleton()
{
}
}
public class SingletonDependedClass
{
public void SomeMethod()
{
...
string str = Singleton.Insatnce.SomeProperty;
...
}
}
Tout d'abord, SingletonDependedClass
doit être refactorisé pour prendre l'instance de Singleton
comme paramètre constructeur:
public class SingletonDependedClass
{
private Singleton _SingletonInstance;
public SingletonDependedClass()
: this(Singleton.Insatnce)
{
}
private SingletonDependedClass(Singleton singletonInstance)
{
_SingletonInstance = singletonInstance;
}
public void SomeMethod()
{
string str = _SingletonInstance.SomeProperty;
}
}
Test de SingletonDependedClass
( bibliothèque de moquages Moq est utilisée):
[TestMethod()]
public void SomeMethodTest()
{
var singletonMock = new Mock<Singleton>();
singletonMock.Setup(s => s.SomeProperty).Returns("some test data");
var target = new SingletonDependedClass_Accessor(singletonMock.Object);
...
}
Exemple tiré d'un livre : Travailler efficacement avec le code hérité
Également donné la même réponse ici: https://stackoverflow.com/a/28613595/929902
Pour exécuter du code contenant des singletons dans un faisceau de test, nous devons assouplir la propriété singleton. Voici comment nous procédons. La première étape consiste à ajouter une nouvelle méthode statique à la classe singleton. La méthode nous permet de remplacer l'instance statique dans le singleton. Nous l'appellerons setTestingInstance .
public class PermitRepository
{
private static PermitRepository instance = null;
private PermitRepository() {}
public static void setTestingInstance(PermitRepository newInstance)
{
instance = newInstance;
}
public static PermitRepository getInstance()
{
if (instance == null) {
instance = new PermitRepository();
}
return instance;
}
public Permit findAssociatedPermit(PermitNotice notice) {
...
}
...
}
Maintenant que nous avons ce setter, nous pouvons créer une instance de test d'un PermitRepository et le définir. Nous aimerions écrire du code comme celui-ci dans notre configuration de test:
public void setUp() {
PermitRepository repository = PermitRepository.getInstance();
...
// add permits to the repository here
...
PermitRepository.setTestingInstance(repository);
}
Vous êtes confronté à un problème plus général ici. S'ils sont mal utilisés, les Singletons entravent la testabiliy.
J'ai fait une analyse détaillée de ce problème dans le cadre d'une conception découplée. Je vais essayer de résumer mes points: