unit testing - C# Moq VerifySet throws Expression is not a property setter invocation for non-trivial setter -
in c#, moq verifyset throwing expression not property setter invocation.
when setter non-trivial, when using setupproperty or setupset.
here trivial example. notice antlers setter trivial , antlers2 setter not trivial.:
public class dancer { public dancer(bool pismale) { ismale = pismale; } private bool _ismale; public virtual bool ismale { { return this._ismale; } private set { this._ismale = value; } } private bool _antlers; public virtual bool antlers { { return this._antlers; } set { this._antlers = value; } } public virtual bool antlers2 { { return this._antlers; } set { // females cannot have antlers if (ismale) this._antlers = value; else this._antlers = false; } } }
here unit tests. second set of 3 (using antlers2) otherwise identical first set of 3 (using antlers). of unit tests using antlers passes test. unit tests using antlers2 throw expression not property setter invocation.
, when using setupproperty thought entirety of property's implementation ignored , replaced moq.
public class dancertests { [fact] public void antlers_nosetup() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; // act sut.object.antlers = true; // assert sut.verifyset(x => x.antlers = true); } [fact] public void antlers_setupproperty() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; sut.setupproperty(x => x.antlers, false); // act sut.object.antlers = true; // assert sut.verifyset(x => x.antlers = true); } [fact] public void antlers_setupset() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; sut.setupset(x => x.antlers = true); // act sut.object.antlers = true; // assert sut.verifyset(x => x.antlers = true); } [fact] public void antlers2_nosetup() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; // act sut.object.antlers2 = true; // assert sut.verifyset(x => x.antlers2 = true); } [fact] public void antlers2_setupproperty() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; sut.setupproperty(x => x.antlers2, false); // act sut.object.antlers2 = true; // assert sut.verifyset(x => x.antlers2 = true); } [fact] public void antlers2_setupset() { // arrange // create mock of class under test var sut = new mock<dancer>(true) { callbase = true }; sut.setupset(x => x.antlers2 = true); // act sut.object.antlers2 = true; // assert sut.verifyset(x => x.antlers2 = true); } }
what non-trivial base class property setters confuse moq's verifyset? using moq 4.7.99, visual studio 2015, targeting .net framework 4.5.2.
thanks help! have benefited stackoverflow!
so looks have confluence of conditions creating weird scenario. may bug worth reporting, i'm not sure. anyway, hitch in giddy seems come setting callbase = true
and/or calling ismale
inside antler2
property setter.
setting callbase = true
creates mockinvocation
every virtual method in class - including ismale
(this important later). on face of not seem big deal turns out is. exception being thrown in moq in setupsetimpl
method. method verifies the last mockinvocation
called moq setter - checking name of last invocation method starts 'set_'.
with normal 'trivial setter' last invocation setter antlers2
have introduced twist. inside setter calling ismale
, since set callbase = true
when created mock there mockinvocation
ismale
property. happens when set antler2
property 'set_antler2' gets added invocation list , when ismale
called inside antler2
property setter 'get_ismale' added invocation list. when setupsetimpl
checks if last invocation setter instead finds getter , panics.
i've tested , confirmed there @ least 2 ways prevent exception. first not set callbase = true
. problem, though, because need mock object pass antler2
property setter base object - entire point of test. other, simpler, solution bypass ismale
property altogether , call backing field directly antler2
property setter this:
if (this._ismale == true) // notice i'm calling _ismale this._antlers2 = value; else this._antlers2 = false;
this works callbase = true
set because not calling ismale
property, , therefore not adding get_ismale
invocation list. instead checking backing field ismale
property uses.
Comments
Post a Comment