I'm testing a class that has an object in it that inherits from an
abstract base class and also inherits from an interface - in the
example code below, it's the MyPresenter.OnLoad method. The method
sets event handlers for two events, one defined in the abstract base
class and one that's defined in the interface.
My test mocks the controller as DynamicMock<IMyController>. This lets
me set up expectations for an event handler to the event defined in
the interface - but my test fails on the event handler getting wired
up for the abstract class event. The mocked object throws an exception
when cast as a ControllerBase object.
System.InvalidCastException: Unable to cast object of type
'Castle.Proxies.IMyControllerProxyf09d4fa4a658425992d11645397d8e3f' to
type 'ControllerBase'..
Example code for this is below. I'd really appreciate any advice.
[TestMethod()]
public void OnViewLoaded_Test()
{
// Arrange
MyPresenter testPresenter = new MyPresenter();
ControllerBase mockController = mocks.DynamicMock<IMyController>();
// set up expectation that during the test, the class
being tested will add
// a handler to the Controller's events and that this event
handler will not be null
mockController.TaskSuspending += null;
LastCall.Constraints(Rhino.Mocks.Constraints.Is.NotNull());
((ControllerBase))mockController.TaskSuspending += null;
LastCall.Constraints(Rhino.Mocks.Constraints.Is.NotNull());
mocks.ReplayAll();
// Act
testPresenter.OnViewLoaded();
// Assert
mocks.VerifyAll();
}
public abstract class ControllerBase
{
/// <summary>
/// Event raised when a task is being started.
/// </summary>
public event EventHandler StartTask;
}
public interface IMyController
{
event EventHandler ChangingTabs;
}
public class MyController : ControllerBase, IMyController
{
public event EventHandler ChangingTabs;
protected virtual void OnChangingTabsChanged(EventArgs e)
{
if (ChangingTabs != null)
{
ChangingTabs(this, e);
}
}
}
public class MyPresenter
{
private MyController controller;
public MyPresenter()
{
controller = new MyController();
}
public void OnLoad()
{
controller.ChangingTabs += this.HandleChangingTabs;
((ControllerBase)controller).StartTask +=
this.HandleStartTask;
}
public void HandleChangingTabs(object sender, EventArgs e)
{
// do something
}
public void HandleStartTask(object sender, EventArgs e)
{
// do something
}
}
--
You received this message because you are subscribed to the Google Groups "Rhino.Mocks" group.
To post to this group, send email to rhino...@googlegroups.com.
To unsubscribe from this group, send email to rhinomocks+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rhinomocks?hl=en.
The question remains, though - when the object that's mocking the
IMyController interface then needs to be cast as a ControllerBase
object, how can a mocked object handle it?
You are correct in your assertion of "...the dependency that you use
mock objects [in order] to avoid", however you can only use a tool
when it fits the purpose -which of course is why you are posting your
question here in the first place ...."does this tool fit my needs?" is
essentially what you are asking.
Here comes the preachy bit ....
I say "YES, this tool does fit your needs" ... but only if you are in
control of the codebase. This is my response because in my opinion
(which we have to remember is only one opinion, and given without full
knowledge of all the facts) is that the design under test is wrong.
It is pretty clear that the code was not developed in a test driven
manner -which in of itself does not make the design wrong, but it does
make the code difficult to test.
It is aso pretty clear that the code does not conform to the SRP
(Single Responsibility Principle), because MyController is also
concerned with some kind of Task and notifying concerned parties about
when this task is starting -this again makes the code difficult to
test.
My first instincts told me that MyController was actuall some kind of
UI Control object, but now I am coming to the conclusion that it is a
controller of the MVC ilk, which is somehow confused with the MVP
pattern. And I now call into question the presenter
implementation .... the Presenter really should not know anything
about the Controller -assuming that this is MVP with an overriding
Controller (again, just one opinion within a sea of such). ...
This has somehow turned into a code review, so I will desist, but I
think what I'm trying to say is that my belief is that the design of
your objects is wrong, and for this reason Rhino Mocks is not the tool
to use for testing them, instead you might be better off manually
constructing your own Mock implementations, instead of using auto-
generated mocks.
I don't mean to offend, or dictate so please treat this post as it was
intended (a constructive criticism, and a bunch of opinions)., thanks.
--
You received this message because you are subscribed to the Google Groups "Rhino.Mocks" group.
To post to this group, send email to rhino...@googlegroups.com.
To unsubscribe from this group, send email to rhinomocks+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rhinomocks?hl=en.
Thanks for taking the time to write such a well-considered response,
Bill and Tim.
--
I have in fact used this to mock Windows.Forms user controls and that
was a mission of note to get that right because I prefer to use stubs.
Anyway, I was able to add a partial multi mock of type
IMyCustomControl into a control's control collection.
Hope this leads you down the right path.
I agree with Bill that when you need to use this, it is already a less
than ideal TDD situation.
On Jan 29, 7:14 pm, Alex McMahon <fluxmu...@gmail.com> wrote:
> I must admit I've only scanned this thread, but have you looked at
> MultiMocks? That's RhinoMocks way of having a single mock that implements
> multiple interfaces... I know yours isn't multiple interfaces, rather
> interface and base class, so I'm not sure it would work, but might be worth
> a try. If I recall AAA syntax supports it something like
> MockRepository.GenerateMock<Interface1, Interface2>()
>
> 2010/1/29 TheMightyKumquat <ree.em...@gmail.com>
>
>
>
>
>
> > Hi, just wanted to say thanks for the replies. No, Bill, your input
> > didn't sound preachy. You're correct that this code wasn't developed
> > in a test-driven manner, and it would have been so much easier if it
> > had been. The sample code is not the real code I'mm testing, but the
> > scenario was accurate, and it is from an MVC pattern web app. I don't
> > really nhave a way around the immediate problem apart from to try to
> > rework the code- we'll see what flexibility I have to do that...
>
> > Thanks for taking the time to write such a well-considered response,
> > Bill and Tim.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Rhino.Mocks" group.
> > To post to this group, send email to rhino...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > rhinomocks+...@googlegroups.com<rhinomocks%2Bunsu...@googlegroups.com>
I did some refactoring of the code being tested and rewrote of the
test. THis passes - apologies if there's a typo in it, it's not the
actual code.
1. Introduced an IControllerBase interface instead of having just an
abstract ControllerBase class
public interface ControllerBase
{
/// <summary>
/// Event raised when a task is being started.
/// </summary>
event EventHandler StartTask;
}
2. Rewrote the code in the class using the controller object to use it
as an IControllerBase instance rather than a ControllerBase instance
public class MyPresenter
{
//...
public void OnLoad()
{
controller.ChangingTabs += this.HandleChangingTabs;
((IControllerBase)controller).StartTask +=
this.HandleStartTask;
}
}
3. Rewrote the test:
[TestMethod()]
public void OnViewLoaded_Test()
{
// Arrange
MyPresenter testPresenter = new MyPresenter();
ControllerBase mockController =
mocks.DynamicMultiMock<IMyController>(typeof(IControllerBase));
// set up expectation that during the test, the class being
tested will add
// a handler to the Controller's events and that this event
handler will not be null
mockController.TaskSuspending += null;
LastCall.Constraints(Rhino.Mocks.Constraints.Is.NotNull());
mocks.ReplayAll();