2010-03-01 3 views
4

J'utilise RhinoMocks, et j'ai un Mock qui a une propriété dont j'ai besoin de se comporter comme une propriété réelle - mettre à jour sa valeur quand il est défini et déclencher PropertyChanged lorsque la propriété est modifiée.Création de mocks trigger PropertyChanged en cas de modification

L'interface de l'objet moqué est en substance ceci:

public interface IFoo 
{ 
    event PropertyChangedEventHandler PropertyChanged; 
    int Bar { get; set; } 
} 

Lors de la création de la maquette, je mis propertybehavior - ce qui en fait réellement mettre à jour sa valeur truquée:

var mocks = new MockRepository(); 
var fakeFoo = mocks.DynamicMock<IFoo>(); 
SetupResult.For(fakeFoo.Bar).PropertyBehavior(); 

Mais quand je mets à jour la valeur PropertyChanged n'est pas déclenchée. Maintenant, l'interface n'implémente pas l'interface INotifyPropertyChanged car il s'agit d'une interface .. Comment puis-je déclencher PropertyChanged?

Répondre

7

Le rôle d'écouteur et de mutateur peut parfois être combiné dans la même classe (par exemple dans un adaptateur), mais les deux rôles ne doivent pas être testés ensemble.

Dans un test, vous vérifiez simplement que votre classe d'écoute réagit à l'événement PropertyChanged tel que conçu. Vous ne se soucient pas de ce qui a causé la propriété de changer dans ce test:

[Test] 
public void Updates_Caption_when_Bar_PropertyChanged() 
{ 
    var foo = MockRepository.GenerateStub<IFoo>(); 
    foo.Bar = "sometestvalue1"; 
    var underTest = new UnderTest(foo); 

    // change property and raise PropertyChanged event on mock object 
    foo.Bar = "sometestvalue2"; 
    foo.Raise(x=>x.PropertyChanged+=null, 
     foo, 
     new PropertyChangedEventArgs("Bar")); 

    // assert that the class under test reacted as designed 
    Assert.AreEqual("sometestvalue2", underTest.Caption); 

    // or if the the expected state change is hard to verify, 
    // you might just verify that the property was at least read 
    foo.AssertWasCalled(x => { var y = foo.Bar; }); 
} 

Dans un autre test, vous vérifiez que votre classe joue son rôle de mutator comme prévu:

[Test] 
public void Reset_clears_Foo_Bar() 
{ 
    var foo = MockRepository.GenerateStub<IFoo>(); 
    foo.Bar = "some string which is not null"; 
    var underTest = new UnderTest(foo); 

    underTest.Reset(); 

    // assert that the class under test updated the Bar property as designed 
    Assert.IsNull(foo.Bar); 
} 

De cette façon, il n'est jamais nécessaire de mettre de la vraie logique dans vos objets simulés comme vous essayez de le faire. Cela nécessite que vous concevez vos classes pour la testabilité; il est difficile d'ajouter de tels tests aux classes existantes. D'où la pratique de test driven development.

1

Je ne suis pas un expert en RhinoMocks, mais je n'essaierais pas de le faire avec l'un des cadres fictifs que je connais (TypeMock que je connais le plus).

Je mettre en œuvre quelque chose comme:

public class FooFake: IFoo 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    int _bar; 
    public int Bar 
    { 
     set 
     { 
      if(PropertyChanged != null) 
       PropertyChanged(); 
      _bar = value; 
     } 
     get 
     { 
      return _bar; 
     } 
    } 
} 

Désolé. Rien de vraiment intelligent. Mais j'aime ce genre de talon car ils peuvent être resusés.

+1

+1 mais ce n'est pas un bout. Le terme de test unitaire pour une implémentation simplifiée créée manuellement est un "faux". Ce post du blog google testing donne quelques bonnes définitions: http://googletesting.blogspot.com/2008/06/tott-friends-you-can-depend-on.html Et cet article de Martin Fowler: http: // martinfowler.com/articles/mocksArentStubs.html –

+0

Vous avez raison. Je dois changer d'habitude pour appeler ce talon! J'ai changé l'exemple maintenant de FooStub à FooFake. – Enceradeira

Questions connexes