How to mock private method?

674 views
Skip to first unread message

Tony Cheung

unread,
Nov 29, 2006, 1:03:13 AM11/29/06
to Rhino.Mocks
Hi,

I have been evaluating Rhino.Mocks for some weeks, and I think it is
great!

However, I got a question yesterday, please refer to the sample below.

public class Obj
{
public Obj() { }

public BeingTested
{
Init();
}

private void Init( )
{ // do something internal
}
}

[TestMethod()]
public void TestContructor()
{
MockRepository _mocks = new MockRepository();
Obj obj = (Obj)_mocks.CreateMock<Obj>();
obj.Init()) // *** compilation error, since Init is private, how
can I tell this is expected to be called?
_mocks.ReplayAll();

obj.BeingTested();
_mocks.VerifyAll();
}

Any help would be grateful! Thanks in advance.

Ayende Rahien

unread,
Nov 29, 2006, 1:54:23 AM11/29/06
to Rhino...@googlegroups.com
You can't mock private (or non-virtual) methods.

Tony Cheung

unread,
Nov 29, 2006, 3:55:05 AM11/29/06
to Rhino.Mocks
So, according to the example, when using Rhino.Mocks, how can I verify
if a private method has been called while the caller method under test?


Thanks for your help !


On Nov 29, 2:54 pm, "Ayende Rahien" <aye...@ayende.com> wrote:
> You can't mock private (or non-virtual) methods.
>

> > Any help would be grateful! Thanks in advance.- Hide quoted text -- Show quoted text -

Ayende Rahien

unread,
Nov 29, 2006, 5:03:29 AM11/29/06
to Rhino...@googlegroups.com
You can't directly.
You need to setup a flag.
The CLR doesn't allow intercepting private methods.

On 11/29/06, Tony Cheung < ton...@gmail.com> wrote:

So, according to the example, when using Rhino.Mocks , how can I verify

Colin Mackay

unread,
Nov 29, 2006, 5:10:43 AM11/29/06
to Rhino...@googlegroups.com
Your TestConstructor() method makes no sense to me. You don't seem to be
testing anything but the mock object.

Also, I'd say that if you are testing a public method that happens to
call private methods within the same class then you don't need to use
mocks because the private method is still in the class under test (CUT).
It is only when the code calls something outside the CUT that mocks
should be used. (Well, in my opinion anyway)


______________________________________________________________________
This email has been scanned by the MessageLabs Email Security System.
For more information please visit http://www.messagelabs.com/email
______________________________________________________________________

Privileged/Confidential information may be contained in this email and is intended for the use of the addressee only.

If you are not the addressee, you may not copy or otherwise use the information.

If you receive this email by mistake, please notify us immediately at: in...@letsure.co.uk

Although this message and any attachments are believed to be free of any virus or other defect that might affect any computer system into which it is received and opened, it is the responsibility of the recipient to ensure that it is virus-free and no responsibility is accepted by either Lumley Letsure Limited (Letsure) or Lumley Limited for any loss or damage in any way arising from its use.

Lumley Letsure Limited Registered in England No. 03010153
Registered Office: Hargrave House Belmont Road Maidenhead Berkshire SL6 6TB
Lumley Letsure Limited is authorised and regulated by the Financial Services Authority. Registration number is 313817.

Lumley Limited Registered in England No. 00378519
Registered Office: Hargrave House Belmont Road Maidenhead Berkshire SL6 6TB
Lumley Limited is authorised and regulated by the Financial Services Authority. Registration number is 314040.

Monique Hawkins

unread,
Nov 29, 2006, 5:13:03 AM11/29/06
to Rhino...@googlegroups.com
If you are trying to test a method on Obj though, why is Obj a mocked object?  Should Obj not be a real object, and just use mocking for any of Obj's dependent objects?
 
Regards,
Monique


From: Rhino...@googlegroups.com [mailto:Rhino...@googlegroups.com] On Behalf Of Ayende Rahien
Sent: 29 November 2006 10:03
To: Rhino...@googlegroups.com

Subject: Re: How to mock private method?
You can't directly.
You need to setup a flag.
The CLR doesn't allow intercepting private methods.

On 11/29/06, Tony Cheung < ton...@gmail.com> wrote:

So, according to the example, when using Rhino.Mocks , how can I verify

Tony Cheung

unread,
Nov 29, 2006, 8:48:51 AM11/29/06
to Rhino.Mocks
Thanks for your reply!

Sorry that I missed some code in my first post, please find what I want
to ask below

public class Obj
{
public Obj() { }


public BeingTested
{
Init();
}


private void Init( )
{ // do something internal
}

}

[TestClass()]
public class ObjTest
{

[TestMethod()]
public void TestContructor()
{
MockRepository _mocks = new MockRepository();
Obj obj = (Obj)_mocks.CreateMock<Obj>();
obj.Init()) // *** compilation error, since Init is private,
how can I tell this is expected to be called?
_mocks.ReplayAll();

obj.BeingTested();
_mocks.VerifyAll();

}
}

Actually, what I want to test is the BeingTested method of the class
Obj, which depends on its private method Init().

As you said that the CUT should not be mocked, may I know the reason
behind it? Since I am still a newbie on unit testing, and going to
learn whatever it need.

Thanks for your help.

Colin Mackay

unread,
Nov 29, 2006, 9:54:05 AM11/29/06
to Rhino...@googlegroups.com
The reason the CUT (class under test) should not be mocked is because it
is the thing being tested. If you mock it then you are not testing it -
you are testing the mock.

If your BeingTested method (which needs parenthesis by the way, unless
it is actually property but missing the get/set) calls an internal
method in the CUT. Since the method is private, I'd normally have that
as part of the test of the public method because it is not outside the
class. The only things I mock are other objects that the CUT calls.

VSTS, which I notice you are using, does do some nice code generation to
allow you to unit test private methods on their own through a special
"Accessor" class, so you can test the workings on the private method in
its own unit test as well.

I'd rewrite your test method as follows:

[TestClass()]
public class ObjTest
{

[TestMethod()]
public void TestContructor()
{
// Set up the environment for the test


MockRepository _mocks = new MockRepository();

Obj obj = new Obj(); // Note this is a real Obj

// ***
// If Init() calls anything outside the class under test
// then set up those mocks here
// ***

// Perform the test
_mocks.ReplayAll();
obj.BeingTested(); // Will call the real Init() method

// Check that the test worked. Add any Asserts necessary
_mocks.VerifyAll();
}
}

-----Original Message-----
From: Rhino...@googlegroups.com [mailto:Rhino...@googlegroups.com]

On Behalf Of Tony Cheung

Sent: 29 November 2006 13:49
To: Rhino.Mocks
Subject: Re: How to mock private method?


Thanks for your reply!


public BeingTested
{
Init();
}

}

[TestClass()]
public class ObjTest
{

obj.BeingTested();
_mocks.VerifyAll();

}
}

Thanks for your help.


______________________________________________________________________
This email has been scanned by the MessageLabs Email Security System.
For more information please visit http://www.messagelabs.com/email
______________________________________________________________________

Privileged/Confidential information may be contained in this email and is intended for the use of the addressee only.

Colin Mackay

unread,
Nov 29, 2006, 9:57:42 AM11/29/06
to Rhino...@googlegroups.com
I just thought of something else.

You could make the Init a virtual protected method - Then RhinoMocks
could replace the Init() with its own mockable version.


public class Obj
{
public Obj() { }

public BeingTested
{
Init();
}

// No longer private:
protected virtual void Init( )
{ // do something internal
}
}

Of course, this changes the CUT slightly so that any class you derive
will have access to the Init() method (something it previously wouldn't
have access to) and you make the class sealed.

-----Original Message-----
From: Rhino...@googlegroups.com [mailto:Rhino...@googlegroups.com]
On Behalf Of Tony Cheung
Sent: 29 November 2006 13:49
To: Rhino.Mocks
Subject: Re: How to mock private method?


Thanks for your reply!


public BeingTested
{
Init();
}

}

[TestClass()]
public class ObjTest
{

obj.BeingTested();
_mocks.VerifyAll();

}
}

Thanks for your help.


Owen Evans

unread,
Nov 29, 2006, 11:44:14 AM11/29/06
to Rhino...@googlegroups.com
It might be worth giving some abstraction for what we are trying to say

If i wanted to test my elevator system for floor 5 (ie the buttons that call the elevator on floor 5) i wouldn't mock the buttons, but the elevator system that recieves the call

so i would test that when i press the up button a call is recieved by the elevator system that says i want to go up
and if i press the down button i exepect a call to say i want to go down.

as such how i arrive from the button press to get to the elevator system doesn't bother me

so i would create a new mock

MockElevatorSystem = mockRepository.CreateMock(IElevatorSystem);

then i would create a new version of my Buttons
ElvButtons ElevatorButtons = new ElevatorButtons(MockElevatorSys
tem);
and then check that when i press up the correct call is received

MockElevatorSystem.CallForUp(5)
MockElevatorSystem.CallForDown(5)

Replay

ElevatorButtons.Down()
ElevatorButtons.Up()

This is what mocking is for... checking that if i call a method i get the correct calls out of the class.
Or for saying i have an entire system around my class that i don't care how it works i just want to check that if my method calls some of these classes and if it gets a correct return (or an incorrect return for negative testing) then it does the correct sequence of actions.


Sorry about the bad example. i'm waiting to leave my own fifth floor and tired. but someone else might be able to give you a better example.

Cheers
Owen Evans

Colin Mackay

unread,
Nov 29, 2006, 11:50:01 AM11/29/06
to Rhino...@googlegroups.com
Sorry - The last sentence in my last email has a mistake in it. It
should read:

Of course, this changes the CUT slightly so that any class you derive
will have access to the Init() method (something it previously wouldn't

have access to) and you **can't** make the class sealed.

public BeingTested
{
Init();
}


Thanks for your reply!


public BeingTested
{
Init();
}

}

[TestClass()]
public class ObjTest
{

obj.BeingTested();
_mocks.VerifyAll();

}
}

Thanks for your help.

Privileged/Confidential information may be contained in this email and is intended for the use of the addressee only.

Tony Cheung

unread,
Nov 30, 2006, 9:24:01 AM11/30/06
to Rhino.Mocks
Thanks for your reply!

I just come up with another question. Instead of a private method, it
is now calling a static method from other class, eg.

// Sign enum
public enum Sign
{ Positive, Negative, Neutral }

// CUT


public class Obj
{
public Obj() { }

public void BeingTested(int condition)
{
if (condition > 0)
SignHelpers.DoSomethingPositive(this);
else if (condition < 0)
SignHelpers.DoSomethingNegative(this);
else
SignHelpers.DoNothing(this);

}

private Sign _sign;
public Sign Sign
{
get { return _sign; }
set { _sign = value; }
}

}
// Helper class provide static helper routines
public class SignHelpers
{
private SignHelpers() { }

public static void DoSomethingPositive(Obj obj)
{
obj.Sign = Sign.Positive;
}
public static void DoSomethingNegative(Obj obj)
{
obj.Sign = Sign.Negative;
}
public static void DoNothing(Obj obj)
{
obj.Sign = Sign.Neutral;
}
}

In this case, if I want to test Obj's BeingTested method, how should I
setup the mocks?

[TestClass()]
public class ObjTest
{
[TestMethod()]

public void PositiveTest()
{
int condition = 10;


MockRepository _mocks = new MockRepository();
Obj obj = new Obj();
//

// *** how should I setup the mocks so that SignHelper's
DoSomethingPositive has
// *** to be called, but not DoSomethingNegative and DoNothing
??
//
// Helpers.DoSomethingPositive(obj); <-- I cannot do this,
since it will make the real call
_mocks.ReplayAll();

obj.BeingTested(condition);
_mocks.VerifyAll();

Assert.AreEqual(Sign.Positive, obj.Sign);
}
}

Thanks for any comments!

- Tony

> For more information please visithttp://www.messagelabs.com/email


> ______________________________________________________________________
>
> Privileged/Confidential information may be contained in this email and is intended for the use of the addressee only.
>
> If you are not the addressee, you may not copy or otherwise use the information.
>

> If you receive this email by mistake, please notify us immediately at: i...@letsure.co.uk


>
> Although this message and any attachments are believed to be free of any virus or other defect that might affect any computer system into which it is received and opened, it is the responsibility of the recipient to ensure that it is virus-free and no responsibility is accepted by either Lumley Letsure Limited (Letsure) or Lumley Limited for any loss or damage in any way arising from its use.
>
> Lumley Letsure Limited Registered in England No. 03010153
> Registered Office: Hargrave House Belmont Road Maidenhead Berkshire SL6 6TB
> Lumley Letsure Limited is authorised and regulated by the Financial Services Authority. Registration number is 313817.
>
> Lumley Limited Registered in England No. 00378519
> Registered Office: Hargrave House Belmont Road Maidenhead Berkshire SL6 6TB

> Lumley Limited is authorised and regulated by the Financial Services Authority. Registration number is 314040.- Hide quoted text -- Show quoted text -

Ayende Rahien

unread,
Nov 30, 2006, 10:57:32 AM11/30/06
to Rhino...@googlegroups.com
You can't mock statics, either.
Only virutal/abstract methods

Owen Evans

unread,
Dec 1, 2006, 4:49:51 AM12/1/06
to Rhino...@googlegroups.com
You have to ask yourself why you want to mock a static method. You should be able to quickly test such methods, and static methods should never be too demanding (usually just one or two lines in my experience) so really what benefit you your testing would mocking such a call provide... would you not just be able to use standard asserts to ensure that after you call the BeingTested method your state of obj is correct.

I think your getting hung up on Mocking as a way to test as apposed to being a helper to general testing.

Benefit Vs Cost.

Cheers
Owen Evans

rossentj

unread,
Dec 1, 2006, 10:44:16 AM12/1/06
to Rhino.Mocks
Amen to Owen's post.

Check this out for a reasonable perspective on testing:
http://behaviour-driven.org/

Tony Cheung

unread,
Dec 1, 2006, 12:21:53 PM12/1/06
to Rhino.Mocks
Thanks for the information !
Reply all
Reply to author
Forward
0 new messages