Can't substitute mock method for real method

1,417 views
Skip to first unread message

Chris

unread,
Oct 20, 2009, 5:21:43 AM10/20/09
to Rhino.Mocks
Hi, everyone.

I'm pretty new to mocking and TDD. I work in VS2008 with MSTest and
Rhino.Mocks 3.6.

Below is the class I'm working on and its test harness below it. I'm
trying to mock the method [FindDataSetInDatabaseRegister]. But I keep
getting the same exception with each approach I try.

As you can see, I'm using the private accessor that MSTest creates. I
don't know if this is the main reason that my test keeps failing on
the setting up of the specific method call.

In approach 1 and 2: if I don't have the mock.ReplayAll(); then the
IDataProvider mock is not used and the method setup fails. If the
[mock.ReplayAll();] is there, then, when the method is recorded, the
mock IDataProvider IS used and the method is partially recorded. Then
the exceptions (noted at the end) are thrown.

In approach 4 ("TRY 4") the recording doesn't cause an error and the
actual test code is executed. But then the mocked method is not
substituted and the real method is called instead.

Could anyone please assist me with this problem?
Thanks
Chris
///////////////////////////////////////////////////////////////////////////////////////

public class WorkProcess
{
internal struct TargetDataSetStruct
{
public Guid DataSet_GUID;
public string ConnectionString;
public override string ToString() { return string.Empty; }
}


internal void RunChecks()
{
//check if the dataset_id
exists
try
{
TargetDataSet = FindDataSetInDatabaseRegister
(DataSet_ID, DAL.DataProvider.GetProvder());
}
catch (Exception ex)
{
var exd = (ex as DataSetNotFoundException);
exd.Data.Add("comm_arg", "-d");
exd.Data.Add("value",
DataSetID);
throw exd;
}
}

internal TargetDataSetStruct FindDataSetInDatabaseRegister(int
DataSet_ID, IDataProvider dp)
{
try
{
TargetDataSetStruct tds = new TargetDataSetStruct();
tds.DataSet_GUID = dp.ReturnGUIDFromIntegerMapping
(DataSet_ID);
tds.ConnectionString =
dp.ReturnConnectionStringFromIntegerMapping(DataSet_ID);
return tds;
}
catch (Exception e)
{
throw new DataSetNotFoundException("Dataset_ID [" +
DataSet_ID.ToString() + "] not found (or another error occured).", e);
}
}

public void ProcessFile()
{
RunChecks();
}
}

/////////////////////////////////////////////////////////////////
[TestClass()]
public class WorkProcessTest3
{


private TestContext testContextInstance;

/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test
run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}

private WorkProcess_Accessor target;
private static MockRepository mock;
private static IDataProvider db;
private static int DataSet_ID = 1;
private static System.Guid exp_value = System.Guid.NewGuid();
private static string exp_conn_string = "test";
private static string loc = string.Empty;

[ClassInitialize()]
public static void WorkProcessTestInitialize(TestContext
testContext)
{
HS3Integration.BusinessLayer.Shared.Globals.ApplicationDir
= System.Environment.CurrentDirectory;

//setup the mock data provider
mock = new MockRepository();

using (System.IO.StreamWriter sw =
System.IO.File.CreateText(System.Environment.CurrentDirectory+"\
\testfile.rsp"))
{
sw.Write("Some text");
}

loc =
HS3Integration.BusinessLayer.Shared.Globals.ApplicationDir;
}

/// <summary>
///A test for ProcessFile that tests whether the method
processes the correct file type
///</summary>
[TestMethod()]
public void ProcessFileShouldProcessTheCorrectFileTypeTest()
{
/* //TRY 1
target = mock.PartialMock<WorkProcess_Accessor>();

db = mock.StrictMock<IDataProvider>();
SetupResult.For(db.ReturnGUIDFromIntegerMapping
(DataSet_ID)).Return(exp_value);
SetupResult.For(db.ReturnConnectionStringFromIntegerMapping
(DataSet_ID)).Return(exp_conn_string);

mock.ReplayAll();

Expect.Call(target.FindDataSetInDatabaseRegister
(DataSet_ID, db)).Return(
new WorkProcess_Accessor.TargetDataSetStruct()
{ DataSet_GUID = exp_value, ConnectionString =
exp_conn_string });
mock.ReplayAll(); */

/* //TRY 2
target = mock.PartialMock<WorkProcess_Accessor>();

db = mock.StrictMock<IDataProvider>();

Expect.Call(db.ReturnGUIDFromIntegerMapping
(DataSet_ID)).Return(exp_value);
LastCall.Repeat.Any();
Expect.Call(db.ReturnConnectionStringFromIntegerMapping
(DataSet_ID)).Return(exp_conn_string);
LastCall.Repeat.Any();
mock.ReplayAll();

Expect.Call(target.FindDataSetInDatabaseRegister
(DataSet_ID, db)).Return(
new WorkProcess_Accessor.TargetDataSetStruct()
{ DataSet_GUID = exp_value, ConnectionString = exp_conn_string });
mock.ReplayAll(); */


/* //TRY 3
target = MockRepository.GenerateMock<WorkProcess_Accessor>
();
db = MockRepository.GenerateMock<IDataProvider>();

db.Stub(x => x.ReturnGUIDFromIntegerMapping
(DataSet_ID)).Return(exp_value);
db.Stub(x => x.ReturnConnectionStringFromIntegerMapping
(DataSet_ID)).Return(exp_conn_string);

var t = new WorkProcess_Accessor.TargetDataSetStruct()
{ DataSet_GUID = exp_value, ConnectionString = exp_conn_string };
target.Stub(x => x.FindDataSetInDatabaseRegister
(DataSet_ID, db)).Return(t); */



// TRY 4
target = MockRepository.GenerateMock<WorkProcess_Accessor>
();
target.Stub(x => x.FindDataSetInDatabaseRegister
(DataSet_ID, HS3Integration.DAL.DataProvider.GetProvder())).Return(
new WorkProcess_Accessor.TargetDataSetStruct()
{ DataSet_GUID = exp_value, ConnectionString =
exp_conn_string });

target.FileTypeCode =
HS3Integration.BusinessLayer.Shared.Constants.ftResponse;
string[] args = { "-p", loc, "-f", "testfile.rsp", "-t",
"rsp", "-d", "01", "-l", @"tinus01\mastermed\mastermed" };
target.SetArguments(args);
target.ProcessFile();
mock.VerifyAll();
}
}



TRY 1
Error msg
Test method
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
threw exception: System.InvalidOperationException: Invalid call, the
last call has been used or no call has been made (make sure that you
are calling a virtual (C#) / Overridable (VB) method)..

Error Stack Trace
Rhino.Mocks.LastCall.GetOptions[T]()
Rhino.Mocks.Expect.Call[T](T ignored)
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
() in E:\Projects\HS3_PMA_BO\HS3_PMA_TestSuite\WorkProcessTest.cs:
line 404



TRY 2
Error msg
Test method
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
threw exception: System.InvalidOperationException: Invalid call, the
last call has been used or no call has been made (make sure that you
are calling a virtual (C#) / Overridable (VB) method)..

Error Stack Trace
Rhino.Mocks.LastCall.GetOptions[T]()
Rhino.Mocks.Expect.Call[T](T ignored)
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
() in E:\Projects\HS3_PMA_BO\HS3_PMA_TestSuite\WorkProcessTest.cs:
line 423



TRY 3
Error msg
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
threw exception: System.InvalidOperationException: Invalid call, the
last call has been used or no call has been made (make sure that you
are calling a virtual (C#) / Overridable (VB) method)..

Error Stack Trace
Rhino.Mocks.LastCall.GetOptions[T]()
R](T mock, Function`2 action)
R](T mock, Function`2 action)
HS3_PMA_TestSuite.WorkProcessTest3.ProcessFileShouldProcessTheCorrectFileTypeTest
() in E:\Projects\HS3_PMA_BO\HS3_PMA_TestSuite\WorkProcessTest.cs:
line 436



TRY 4
Doesn't throw the previous errors. But the mock isn't used at all.
The call gets through
to the DAL method instead of the mocked FindDataSetInDatabaseRegister-
method (which is invoked much earlier).

Alex McMahon

unread,
Oct 20, 2009, 5:53:56 AM10/20/09
to rhino...@googlegroups.com
A few points:
  1. To mock a method on a class it must be marked as virtual (FindDataSetInDatabaseRegister is not virtual therefore you can't mock it).
  2. Are you sure that's the method you want to mock? it sort of looks like you want to mock the calls to dp.xxxx within that message... if so then you need a way to replace the IDataProvider that is passed into the method. This is currently retrieved from DAL, which I guess is some sort of static?
  3. All your test methods create a mock IDataProvider (db) but then never pass this mock into the target. Therefore the mock is never hit. You might want to use Dependency Injection to inject your mock (or real IDataProvider) into the target. Alternatively you could change your DAL class to allow your mock to be returned (I personally wouldn't do this)
  4. Usually you wouldn't mock your target, you mock the dependencies of your target instead.
  5. Why do you need a private accessor? can't you just create an instance of your target, then call ProcessFile on it (seeing as it's public)
  6. A lot of what you've got there doesn't exactly look normal, try looking at Rhino Mocks documentation or some open source projects that use Rhino Mocks to see some examples of how to use it
Hope some of that helps.

2009/10/20 Chris <chris.m...@gmail.com>

Chris

unread,
Oct 20, 2009, 9:41:41 AM10/20/09
to Rhino.Mocks
Hi, Alex.
Thanks for the reply.

1. I agree with you on this point, however, since the private accessor
exposes the given methods as "public" I thought it unnecessary to add
the "virtual".
I added the "virtual", still the same exception; failure on the same
Expect.Call().

2. Yes. My target is the "ProcessFile"-method. ProcessFile calls
RunChecks which calls FindDataSetInDatabaseRegister.
I'm trying to mock away the dependency that ProcessFile has on
FindDataSetInDatabaseRegister and FindDataSetInDatabaseRegister on the
IDataProvider.

3. In another test, not shown here, I do use the DI pattern with the
IDataProvider correctly. I was hoping that by mocking the
IDataProvider again in this test, that the mocking framework will
automatically substitute the IDataProvider when those calls are hit.
Am I too optimistic in this expectation?

4. Agreed. That's what I'm trying to do - mock away ProcessFile's
dependency on FindDatasetInDatabaseRegistry.

5. The FindDatasetInDatabaseRegistry-method is marked internal and
calls the DAL which throws a System.NotImplementedException. This is
a business unit test, not DAL test, so I want to mock away that
dependency. Just calling ProcessFile (without mocking certain
methods) in the test will just throw the DAL exception.

6. Will do. Unfortunately my googling hasn't scared up a similar
case.

Given my code posted in the thread, could you perhaps knock something
together to show how you might approach it? The IDataProvider
interface is just the two methods that FindDatasetInDatabaseRegistry
call.

On Oct 20, 11:53 am, Alex McMahon <fluxmu...@gmail.com> wrote:
> A few points:
>
>    1. To mock a method on a class it must be marked as virtual
>    (FindDataSetInDatabaseRegister is not virtual therefore you can't mock it).
>    2. Are you sure that's the method you want to mock? it sort of looks like
>    you want to mock the calls to dp.xxxx within that message... if so then you
>    need a way to replace the IDataProvider that is passed into the method. This
>    is currently retrieved from DAL, which I guess is some sort of static?
>    3. All your test methods create a mock IDataProvider (db) but then never
>    pass this mock into the target. Therefore the mock is never hit. You might
>    want to use Dependency Injection to inject your mock (or real IDataProvider)
>    into the target. Alternatively you could change your DAL class to allow your
>    mock to be returned (I personally wouldn't do this)
>    4. Usually you wouldn't mock your target, you mock the dependencies of
>    your target instead.
>    5. Why do you need a private accessor? can't you just create an instance
>    of your target, then call ProcessFile on it (seeing as it's public)
>    6. A lot of what you've got there doesn't exactly look normal, try
>    looking at Rhino Mocks documentation or some open source projects that use
>    Rhino Mocks to see some examples of how to use it
>
> Hope some of that helps.
>
> 2009/10/20 Chris <chris.medem...@gmail.com>
>

Alex McMahon

unread,
Oct 20, 2009, 10:56:07 AM10/20/09
to rhino...@googlegroups.com
1. Public not enough for mocking a class, needs to be virtual. Mocking
interfaces is sooooo much more easier than mocking classes; I never
mock classes, not worth the headache.
2. I'm still not sure you want to mock that, as it's part of the class
you're trying to test, usually it's best to leave private methods
below because it's an implementation detail private to the class. If
your test digs into the private parts of a class the test/class will
be very brittle... better to try and see your class as a complete
object and only mock the dependencies of the class, not its private
methods.
3.Too optimistic, just creating a mock doesn't mean it get used, you
need to pass it to something, whether that's the class itself (usual
way) or to some sort of Service Locator or IoC container.
4. Note in my test below I don't mock WorkProcess at all... that's
kind of what I was getting at
5. I've removed the dependency on DAL by passing in an IDataProvider
explicitly, your next question might be that in production you want it
to access the DAL, in which case there are several possibilities
including "poor man's dependency injection" where you have another
constructor used only in production which uses DAL to populate the
dependency. Or you could use an IoC container...

This is roughly what I'd do (complete example, note no private accessor needed):

public interface IDataProvider
{
Guid ReturnGUIDFromIntegerMapping(int id);
string ReturnConnectionStringFromIntegerMapping(int id);
}

public class WorkProcess
{
public struct TargetDataSetStruct
{
public Guid DataSet_GUID;
public string ConnectionString;
}

public TargetDataSetStruct TargetDataSet
{
get;
private set;
}

public int DataSet_ID
{
get;
set;
}

private IDataProvider dp;

public WorkProcess(IDataProvider dp)
{
this.dp = dp;
}

internal void RunChecks()
{
TargetDataSet = FindDataSetInDatabaseRegister(DataSet_ID, dp);
}

internal TargetDataSetStruct FindDataSetInDatabaseRegister(int
DataSet_ID, IDataProvider dp)
{
TargetDataSetStruct tds = new TargetDataSetStruct();
tds.DataSet_GUID = dp.ReturnGUIDFromIntegerMapping(DataSet_ID);
tds.ConnectionString =
dp.ReturnConnectionStringFromIntegerMapping(DataSet_ID);
return tds;
}

public void ProcessFile()
{
RunChecks();
}
}

[TestClass()]
public class WorkProcessTest
{
[TestMethod()]
public void ProcessFileShouldPopulateDataSetGuid()
{
//Arrange
IDataProvider mockDP = MockRepository.GenerateMock<IDataProvider>();
WorkProcess target = new WorkProcess(mockDP);
int id = 5;
target.DataSet_ID = id;
Guid expected = Guid.NewGuid();
mockDP.Stub(x => x.ReturnGUIDFromIntegerMapping(id)).Return(expected);

//Act
target.ProcessFile();

//Assert
Assert.AreEqual(expected, target.TargetDataSet.DataSet_GUID);
}
}

2009/10/20 Chris <chris.m...@gmail.com>

Chris

unread,
Oct 21, 2009, 9:53:58 AM10/21/09
to Rhino.Mocks
Yes, you are right. I'm trying to mock something that shouldn't be
mocked. Also, I've been so caught up with this that I didn't remember
to fully utilize the DI pattern. Moving the data provider dependency
to look like yours is also more elegant and easier to test.

Thank you very much for your help. My test now passes and I've gain
better insight.
Much appreciated.

Chris

Reply all
Reply to author
Forward
Message has been deleted
0 new messages