devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
0 2 minut

Testowanie setterów w fakeiteasy


19.12.2011

Na dzień dzisiejszy wybierając „mocking framework” stawiam właśnie na fakeiteasy. Ma ona jeden ciemny zakamar, w którym można nieźle pobłądzić… a jest to testowanie wywołania settera.

Załóżmy, że mamy jakiś interfejs wymuszający na implementacjach posiadanie właściwości Age:

  1:  public interface IHaveAge
  2:  {
  3:      int Age { get; set; }
  4:  }

I test „jakiejś klasy” przetwarzającej implementacje tego interfejsu, mającej ustawić wartość wspomnianej właściwości:

  1:  [Fact]
  2:  public void sets_age_to_18_during_processing()
  3:  {
  4:      var withAge = A.Fake<IHaveAge>();
  5:  
  6:      new TestedClass().Process(withAge);
  7:  
  8:      A.CallTo(() => withAge.Age = 18)
  9:          .MustHaveHappened();
 10:  }

Wydaje się w porządku? Otóż nie jest. Kompilator zgłosi, że jesteśmy fe:

Error    5    An expression tree may not contain an assignment operator

Sam powyższy scenariusz jest jeszcze w miarę prosty, bo przypisanie konkretnej wartości do settera możemy przetestować w „normalny” sposób – fakeiteasy zapamiętuje przypisanie i konfiguruje mocka tak aby zwracał aktualnie nadaną właściwości wartość:

  1:  [Fact]
  2:  public void sets_age_during_processing()
  3:  {
  4:      var withAge = A.Fake<IHaveAge>();
  5:  
  6:      new TestedClass().Adapt(withAge);
  7:  
  8:      Assert.Equal(18, withAge.Age);
  9:  }

 

Ale problem pojawia się, jeśli chcemy przetestować sam fakt wywołania settera, a nie jego aktualną wartość. Sytuacja taka może być na nas wprost wymuszona, na przykład jeśli mockujemy interfejs z zewnętrznej biblioteki i ma on właściwość write-only, bez gettera (rzadki przypadek, ale się zdarza). Jedynym chyba sposobem na napisanie takiego testu w fakeiteasy jest poniższy brzydal:

  1:  [Fact]
  2:  public void sets_age_during_processing()
  3:  {
  4:      var withAge = A.Fake<IHaveAge>();
  5:  
  6:      new TestedClass().Adapt(withAge);
  7:  
  8:      A.CallTo(withAge)
  9:          .Where(x =>
 10:                  x.Method.Name == "set_Age"
 11:                  // if we want to test the value as well
 12:                  // && x.GetArgument<int>(0) == 18
 13:      ).MustHaveHappened();
 14:  }

Okropne, ale… nie znalazłem lepszego sposobu (nie tylko ja, wiem że i Gutek trochę nad tym posiedział…).

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Powiadom o
dooh
dooh

Co do 3. przypadku, to brzydka wydaje mi się koncepcja interfejsu z setterem typu write-only (nie udostępniającego sposobu na sprawdzenie skutków takiego wywołania). Nie dziwi mnie dlatego, że konfiguracja mocka jest w tym wypadku równie brzydka :]

procent

dooh,
Prawda, chociaż np w Moq da się do zapisać ładniej, bez stringów ( http://stackoverflow.com/questions/1641919/moq-how-to-verify-that-a-property-value-is-set-via-the-setter ).

Moja książka „Zawód: Programista”

Facebook

Zobacz również