chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
OK, I've reviewed the simple mocking demos and understand at a pretty high level what mocking is supposed to do.

However, in trying to set up even a basic mock test for a database-driven business object, I find it incredibly cumbersome to do any real testing.

If I have a Customer object with ten properties, some of which are not public, some of which are also read only (they are calculated or derived values from other data), I find it very difficult to even know where to begin.

First, if I want to test adding say, an invoice to the Invoices collection of the Customer, I need to have a Customer object already constructed in a valid state. So, I need to manually set the non-public and read only properties in some way and this can be error-proned from a business rules point of view. Next, I would need to do the same for the Invoice I'm adding. At the end of the day, I would have to do a lot of hacking to come up with a stub for these two objects and figure out how to hydrate the Customer object with dummy/stub data. Or do the setters/getters in TypeMock already do this, even for private data?

I'm probably trying to use mocking beyond the narrow scope it is intended to address in automated testing. I get the need to be able to mock certain things like a logger, but for data driven classes, I still think your best option is to always do an integration test with a small database that is very small (and thus, faster to restore from) and then just restore to a pristine state at the end of each test run.

I'd love to see some basic examples of mocking business objects that are normally data-driven. I imagine this use case includes 99% of business app dev.
asked by SultanOfSuede (640 points)

3 Answers

0 votes
Well, it's all about the isolation principal. You are interested in unit testing your (say) invoice management object. In order to satisfy the code you'd need to create objects around it - customers, invoices, etc. - a whole bunch of stuff you aren't interested in doing when unit testing.

This is where the beauty and strength of the mocking framework is put to play: you don't need to actually create all these objects. You can replace them with fakes, stubs and mocks very easily using the frameworks' API. Using Typemock Isolator you can also mock private, protected and static calls (and pretty much anything you can think of) so there's no real concern there.

For instance, lets say this is the code being tested:
public void DoSomething(IInvoice invoice, string customerId)
{
   Customer customer = DataAccessLayer.FetchCustomer(customerId);
   customer.AddInvoice(invoice);
}


For purpose of unit testing, we need to eliminate dependency on the database; we also don't really need a fully fledged invoice and customer - we just want to make sure the invoice was handled properly. A test's code could be something like this:

public void InvoiceIsAddedAndShipped()
{
   // create a mock Customer
   Customer mockCustomer = RecorderManager.CreatedMockedObject<Customer>();
   // create a mock invoice
   IInvoice mockInvoice = RecorderManager.CreatedMockedObject<IInvoice>();

   // record expectations. calls made in here are not really made!
   using(RecordExpectations rec = RecorderManager.StartRecording())
   {
      // stub out the call to the data access layer
      DataAccessLayer.FetchCustomer(""); // we don't really care what the customer's id is in this test
      // now have it return our mock customer
      rec.Return(mockCustomer);

      // set an expectation on Customer.AddInvoice()
      mockCustomer.AddInvoice(mockInvoice);
      // make sure the correct invoice has been passed in
      rec.CheckArguments();
   }

   // up until now we set up our expectations. now we will run the test
   TestedClass underTest = new TestedClass();
   underTest.DoSomething(mockInvoice, "doron");

   // now that the test is run, verify our expectations were met
   MockManager.Verify();
}


Note that without the comments this example would be much more compact. In the example I mocked out a static call, an interface and a concrete class - instantiating and maintaining all these objects, as well as loading and rolling back database state would be much more of a hassle.

You can find more hands on examples on our media page: https://www.typemock.com/Multimedia.html.

Does this prove the point?

Doron,
Typemock Dev Team
answered by doron (17.2k points)
0 votes
Thanks for the reply. I tried my own little test:

Using Northwind, I created a simple Customer class having an Orders collection containing Order objects.

So, I have: Customer->Orders

I create a mocking test for just the Orders. Orders is a collection class extending BindingList<T> from System.Component. It also implements IBindingListView from the same namespace.

My test is VERY simple and uses reflective mocking:

[Test()]
public void CustomerTest_LoadTest()
{
Mock<Order> mockOrder = MockManager.Mock<Order>();
Mock<Orders> mockOrders = MockManager.Mock<Orders>();

mockOrders.ExpectCall("Add").Args(mockOrder);
}

I get this exception:

"Cannot mock methods defined in types from mscorlib assembly."

Unfortunately, this is an incredibly simple set of classes I put together and TypeMock has problems with it. It's likely that I'm not just not seeing a problem in my test. (The integration test I execute and which loads real data from the SQL database works fine.) I'm not sure how I could make it any simpler, short of chucking any inheritance from System namespaces. Obviously, this isn't feasible.

It appears from my limited understanding that mocking has definite limits as to what it can be used to test.

Of course, I could be wrong ;)
answered by SultanOfSuede (640 points)
0 votes
Hi,

You've come up with a case that is very simple, but displays one of Typemock's few limitations: Typemock Isolator cannot mock implementations of types that are defined in MSCorLib (system.DLL). If you look here, you'll see that the type is declared in that assembly. What you are trying to do is set an expectation on a method (Add) which is defined in MSCorLib, and that is not possible right now.

The easiest way to work around this issue is to wrap the method you want to mock in a function of your own. Because this wrapper would be in your assembly, you would not have any problem mocking it.

I understand your frustartation, setting a small test, trying to make it work. Apart from the explanation above, I want to point you to the examples that are installed with Isolator. There are a lot of them, and they portray different features. Specifically start with Test1_Basics up to Test5_MockObjects.

I'd also encourage you to select a problem that you want to test, and post it here, test and code. I'm emphaisizing test, and not just playing with mocks, so we can put an example with context. I think that we can help you get on track using Isolator for your purposes quickly.
answered by gilz (14.5k points)
...