Moling DataContext with MS Moles?

2020-07-12 07:46发布

问题:

How can I mole the DataContext that I'm using in a class to write messages to a table. I'd like to assert that the table LINQ is writing to has the expected count of messages. Here's what i have so far.

var context = new MJustTestingDataContext();
MyMessagewriter writer = new MyMessageWriter(context);

var messageList = new List<MIncmoingMessage>();
MTable<MIncomingMessage> messageTable = new MTable<MIncomingMessage>();
messageTable.Bind(messagesLinqList.AsQueryable());

If I use this code with xUnit in my class under test I'll get this exception

Microsoft.Moles.Framework.Moles.MoleNotImplementedException: DataContext.Dispose() was not moled.

What am I missing here and how to implement DataContext.Dispose() on the mole? I'm using moles standalone without Pex.

回答1:

When you create a new Mole the default behavior for its methods and properties is to throw a MoleNotImplementedException whenever they are called.

To implement the mole you can do context.Dispose = () => {}; which means that nothing happens when the Dispose method gets called on the moled instance. I reread the question and you probably are having a problem since Dispose is defined in a base class. To mole base method you need to do the following:

var context = new MJustTestingDataContext();
var baseContext = new MDataContext(context);

baseContext.Dispose = () => {};

You'll need to implement every property/method that gets called by the code under test or you can set the default behavior for the mole instance globally using the method BehaveAsDefaultValue. This way every method in the mole will do nothing and return the default value for it's return type if one exists instead of throwing a MoleNotImplementedException. However if you require this behavior it's better to use a stub than a mole.



回答2:

I'm having trouble understanding what your test is doing. I had to do something similar yesterday, so I'll share my experience. First, it's important to understand that you don't need to use all the MoleTypes to test your code -- you just need to use Moles to redirect certain parts of your code to lambda expressions. Given a method that does this:

  1. get a list of users to modify from the database
  2. modify every user in the set
  3. send the new set back to the database

I'd like to redirect 1 and 3 to not use the database. For instance, I can redirect the call to SubmitChanges (3) via this code:

bool hitSubmitChanges = false;
int changeCount = 0;
IList<object> updates = null;

// more code here... 

   // redirect DataContext.SubmitChanges() to a lambda to catch updates 
   MDataContext.AllInstances.SubmitChanges = (c) =>
   {
    changeCount = c.GetChangeSet().Updates.Count;
    updates = c.GetChangeSet().Updates;
    hitSubmitChanges = true;
   };

That (and the call to get the users) would be the only Moletypes I'd use in the test. The rest of it would be normal. Then I can use assertions to check the values of changeCount, updates and hitSubmitChanges.