Reputation: 47
I've done extensive research on this topic and have yet to find a reliable answer so here goes.
I have a constructor I'd like to test. This constructor initializes another class in order to set a global variable which is necessary throughout the rest of the class. However, the constructor of the class which the constructor initializes has dependencies on things like web session and other variables being set which are not set when the any tests run. How can I properly mock this to make sure I'm just testing the constructor?
Here's the constructor to be tested:
public CheckoutManager()
{
_orderController = new OrderController();
_orderController.PropertyChanged += (sender, args) => NotifyPropertyChanged(args.PropertyName);
}
The problem lies in the OrderController constructor:
public OrderController()
{
_customer = WebUserSession.Current.Profile.Customer;
_srd = ContextManager.GetStandardRequestByCulture( CultureInfo.CurrentUICulture.Name );
WarehouseData data = new WarehouseData();
data.WarehouseID = 0; // TODO: Convert the 0 warehouse to a web warehouse type
// Grab the attention items from the session
AttentionItems = WebUserSession.Current.OrderAttentionItems;
// Load the shopping cart
_cart = ShoppingCartManager.Cart;
}
Here is my attempted test:
[TestMethod]
public void Constructor_ExpectInstantiation()
{
var checkoutManager = new CheckoutManager();
Assert.IsNotNull( checkoutManager );
}
It bombs out at the _customer = WebUserSession.Current.Profile.Customer; line. How do you mock this using Moq? If it cannot be mocked, is there a good explanation as to why? How could the original constructor be modified to have the same functionality in a more testable way? Thank you in advance.
Upvotes: 0
Views: 5169
Reputation: 993
You won't be able to use Moq test to this code. You could
Upvotes: 0
Reputation: 9201
You can use Dependency Injection
, which is a form of Inversion of Control, to solve these kind of problems.
Instead of instantiating your OrderController
in the constructor, pass it as an argument:
public CheckoutManager(OrderController orderController)
{
_orderController = orderController;
_orderController.PropertyChanged += (sender, args) => NotifyPropertyChanged(args.PropertyName);
}
You can then either instantiate the OrderController
either manually somewhere in a Main
-like method, or with a library like Autofac
which will do all the wiring for you.
So now you can mock your interface in your test:
[TestMethod]
public void Constructor_ExpectInstantiation()
{
Mock<OrderController> mockOrderController = new Mock<OrderControler>();
var checkoutManager = new CheckoutManager(mockOrderController.Object);
Assert.IsNotNull( checkoutManager );
}
That way, the constructor of OrderController
will never be called (it's a mock) and it won't interfere with your tests of CheckoutManager
. If you need to test some interactions with it, you can Setup
and Verify
specific methods using Moq.
Upvotes: 4