|
From: Owen R. <OR...@th...> - 2004-09-17 03:53:49
|
hi levi and jim, sorry for the slow response. i only recently got back from trekking in the himalayas :) i finally got around to committing jim's changes -- sorry it took so long. jim: i decided not to rely on the order of the method in the stacktrace to identify ref parameters. instead, i used reflection on the mocked type to match the method/property to be invoked. from that i could determine if the parameter was ref or not. this, however, required doing considerable refactoring of the signature class, which took longer than i had intended. > That reminded me that I should've sent you a message before committing in my stuff :) . don't worry -- no need. you don't need to confirm your changes with me, any more than you need to confirm them with any member of the dev team. as a committer, we trust you to do the right thing -- and, if that screws me because i was slow checking in my changes, then the fault is mine :) > I added the proxy mock primarily to be able to mock service proxies generated web by web references, since they don't have any virtual methods. I think it's going to be useful in many other cases as well, since a lot of potentially mockable types are in fact MarshalByRef as most behavior objects should theoretically be. i was thinking about doing this awhile ago, while playing with contextboundobjects and messagesinks. so, i think it is definitely a useful addition to nmock. as far as mocking web services are concerned, the way that we do it on my current project is to have both the proxy class and the web service class implement the same interface. this allows us to easily inject mocks that implement the interface so that we can stub out the web service. for ATs, this also allows us to bypass the overhead of making a web service call (all the marshalling to soap messages and back again really slows the tests down) by having the client call the web service class directly (we're using StructureMap). > Currently a non-strict mock returns null for all unexpected calls (by the it breaks in dynamic mock when return type is a value type). In many cases this behavior is not quite useful. i agree with your concerns about non-strict mocks. i've found that non-strict mocks can often create/conceal errors in the underlying code. plus, i think that it is pretty ambiguous as to what is meant by "strict" (i keep forgetting :) what i think would be vastly more useful is a mechanism whereby you don't have to explicitly specify the parameters for mocked methods. this feature was there (inadvertently or not) in the nmock 1.0 release, but ended up getting removed/changed subsequent to that. as a result, upgrading from nmock 1.0 to newer versions caused a considerable effort due to the amount of modifications to existing tests. IMO, you should only need to specify parameters if a) you want to verify them (using constraints or otherwise) b) there is are overloaded methods, so you need to specify parameters to indicate which method should have expectations set. i believe that jmock is designed with this approach in mind. so, in summary, i'm not sure about the UnexpectedCallAction enum. my preference would just be to remove the Strict property -- or at the very least change the default behaviour to be non-strict. but i would run it by joe, chris and steve first to see what they had in mind with it. cheers, owen. ps. i think that we should consider making a new nmock release (1.2) soon. any further changes that anyone wants to get in before the release? --- R. Owen Rogers ThoughtWorks Technologies (India) Pvt Ltd. ThoughtWorks - Deliver with passion! ThoughtWorks is always looking for talented people who are passionate about technology. To find out more about a career at ThoughtWorks go to http://www.thoughtworks.com/career/. Levi Khatskevitch 03/09/2004 20:08 To: Owen Rogers/Canada/ThoughtWorks@ThoughtWorks cc: Jim Arnold/UK/ThoughtWorks@ThoughtWorks Subject: NMock ideas Hi Owen, I met Jim Arnold at the TAP workshop in Redmond this week, he mentioned that you are working on merging his recent changes to NMock with mine. That reminded me that I should've sent you a message before committing in my stuff :) . I hope you don't have problems with the changes I made so far. I added the proxy mock primarily to be able to mock service proxies generated web by web references, since they don't have any virtual methods. I think it's going to be useful in many other cases as well, since a lot of potentially mockable types are in fact MarshalByRef as most behavior objects should theoretically be. I'm preparing another check-in with more unit test and a couple of minor bug fixes for the proxy mock that I missed the first time. A bigger change that I am contemplating right now is the following: Currently a non-strict mock returns null for all unexpected calls (by the it breaks in dynamic mock when return type is a value type). In many cases this behavior is not quite useful. For example I was trying to mock a base user control class that provided a couple of virtual methods implemented by several derived user controls. Adding such mock to the controls collection of its parent causes numerous calls to inherited virtual members that are not expected and therefore return null confusing the control collection. A work around would be find ignore all those methods and properties but there's quite a few of making this approach less than perfect, so ended up writing a custom mock with only those methods overridden. Ideally I would like non-strict mocks (dynamic or proxy) to delegate unexpected calls back to the stub (its base in dynamic mock case). However, since as Jim had noticed such a change would affect existing NMock semantics (in particular when the base class method has a side effect) , I'm thinking of a way to make this behavior available on demand rather than by default. I suppose we could add a property of an enumerated type like UnexpectedCallAction that excepts values Ignore, Forbid and DelegateToStub. We could then bind the Strict property to this new one in the following way: Strict returns true only when UnexpectedCallAction is set to Forbid, when Strict is set to false (default) it sets UnexpectedCallAction to Ignore. Here's what I mean: private UnexpectedCallAction unexpectedCallAction; public virtual UnexpectedCallAction UnexpectedCallAction { get { return unexpectedCallAction; } set { unexpectedCallAction = value; } } public virtual bool Strict { get { return unexpectedCallAction == UnexpectedCallAction.Forbid; } set { unexpectedCallAction = value? UnexpectedCallAction.Forbid : UnexpectedCallAction.Ignore; } } Eventually we'd mark the Strict property as obsolete and after that remove it. Using delegation to stub with proxy mock will enable simple hand written stubs (wrapped in proxy mock) emulate sealed types (like SqlCommand) or type with non-virtual members. I'm interested in your feedback before I commit my changes this time. Thank you, - Levi |