2009-01-01 10 views
1

J'écris des tests unitaires pour ma classe de présentation dans MVP pattern.Mais j'ai du mal à écrire le code de configuration fictif.Comment puis-je faire face à trop de fausses attentes dans les tests unitaires?

J'ai un présentateur et quand la méthode de charge du présentateur appelée Je veux tester la vue devrait charger les propriétés de classe, les champs de table, les types de données, le présentateur .... Alors quand j'ai autre chose à faire avoir à ajouter de nouvelles attentes à tester. Et le test s'agrandit à chaque fois.

[Test] 
    public void When_Presenter_Loads_View_Should_Display_Selected_Class_Properties() 
    { 
     IList<string> dataTypes =new List<string>(); 
     IClassGenerationView view = mockRepository.StrictMock<IClassGenerationView>(); 
     tableRepository = mockRepository.Stub<ITableRepository>(); 

     using(mockRepository.Record()) 
     { 
      SetupResult.For(tableRepository.GetDataTypes()).Return(dataTypes); 
      view.Presenter = null; 
      LastCall.IgnoreArguments(); 
      view.DataTypes = dataTypes; 
      view.Show(); 

      view.ClassProperties = classProperties; 
      view.TableName = "Table"; 
      view.Table = table; 
      LastCall.IgnoreArguments(); 
     } 


     using(mockRepository.Playback()) 
     { 
      ClassGenerationPresenter presenter = new ClassGenerationPresenter(view, clazz, tableRepository); 
      presenter.Load(); 
     } 
    } 

Y at-il une odeur de code dans ce code? Comment puis-je améliorer ou simplifier cela?

Répondre

1

Après une longue nuit d'insomnie et de recherche, j'ai trouvé cette solution. Quand j'ai réfléchi, j'ai pensé à cela. Je teste trop de comportement dans un test. Et je l'ai changé les essais comme celui-ci

[TestFixture] 
public class When_Presenter_Loads 
{ 
    private MockRepository mockRepository; 
    private ITableRepository tableRepository; 
    private IClass clazz; 
    private Dictionary<string, Type> properties; 
    private IClassGenerationView view; 
    private ClassGenerationPresenter presenter; 

    [SetUp] 
    public void Setup() 
    { 
     mockRepository =new MockRepository(); 
     properties = new Dictionary<string, Type>(); 

     clazz = mockRepository.DynamicMock<IClass>(); 
     view = mockRepository.DynamicMock<IClassGenerationView>(); 
     tableRepository = mockRepository.Stub<ITableRepository>(); 


    } 

    [Test] 
    public void View_Should_Display_Class_Properties() 
    { 
     using(mockRepository.Record()) 
     { 
      SetupResult.For(clazz.Properties).Return(properties); 
      view.ClassProperties = properties; 
     } 

     using(mockRepository.Playback()) 
     { 
      presenter = new ClassGenerationPresenter(view, clazz, tableRepository); 
      presenter.Load(); 
     } 
    } 

    [Test] 
    public void View_Should_Display_Class_Name_As_A_Table_Name() 
    { 
     using (mockRepository.Record()) 
     { 
      SetupResult.For(clazz.Name).Return("ClassName"); 
      view.TableName = "ClassName"; 
     } 

     using (mockRepository.Playback()) 
     { 
      presenter = new ClassGenerationPresenter(view, clazz, tableRepository); 
      presenter.Load(); 
     } 
    } 

    [Test] 
    public void View_Should_Display_SQL_Data_Types() 
    { 
     List<string> dataTypes = new List<string>(); 

     using(mockRepository.Record()) 
     { 
      SetupResult.For(tableRepository.GetDataTypes()).Return(dataTypes); 
      view.DataTypes = dataTypes; 
     } 

     using(mockRepository.Playback()) 
     { 
      presenter = new ClassGenerationPresenter(view, clazz, tableRepository); 
      presenter.Load(); 
     } 
    } 

    [Test] 
    public void View_Should_Show_Table() 
    { 
     using (mockRepository.Record()) 
     { 
      SetupResult.For(clazz.Name).Return("ClassName"); 
      view.Table = null; 
      LastCall.IgnoreArguments(); 
     } 

     using (mockRepository.Playback()) 
     { 
      presenter = new ClassGenerationPresenter(view, clazz, tableRepository); 
      presenter.Load(); 
     } 
    } 
} 

Je l'ai utilisé beaucoup de simulation dynamique pour tester un comportement à la fois. Aussi, vous pouvez lire l'article One Mock Per Test de Dave à ce sujet

+0

Pourriez-vous s'il vous plaît marquer cette réponse comme la bonne réponse? Merci! – guerda

2

J'ai lutté avec cela pendant des années. Au début, j'ai utilisé le modèle MVP, mais je suis passé au modèle de présentation (similaire à MVVM pour WPF/Silverlight) plus tard. Quoi qu'il en soit, les résultats n'ont jamais été satisfaisants, en particulier dans les projets Agile où l'interface utilisateur change rapidement. Par conséquent, nous n'écrivons plus de tests pour ces types de classes et nous sommes passés à SpecFlow/WaTiN pour créer des tests d'interface utilisateur automatisés encore maintenables. En savoir plus à ce sujet ici: http://www.codeproject.com/Articles/82891/BDD-using-SpecFlow-on-ASP-NET-MVC-Application

Si vous voulez toujours écrire des tests pour la logique de l'interface utilisateur, je n'utiliserais certainement pas une méthode d'installation pour supprimer certains éléments de votre test. Il est essentiel que vous soyez en mesure de comprendre la cause et l'effet d'un test sans avoir à naviguer de haut en bas. Au lieu de cela, utilisez un plus test unitaire de style BDD comme je l'ai expliqué dans ce billet de blog: http://www.dennisdoomen.net/2010/09/getting-more-out-of-unit-testing-in.html

En général, j'utilise ces tests de style BDD pour les classes qui sont très orchastrational par nature, et plus de style AAA tests pour les classes ordinaires.