129

I have an object I'm trying to mock using moq. The object's constructor has required parameters:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}

Now I'm trying to create the mock for this object using either moq's v3 "setup" or v4 "Mock.Of" syntax but can't figure this out... everything I'm trying isn't validating. Here's what I have so far, but the last line is giving me a real object, not the mock. The reason I'm doing this is because I have methods on the CustomerSyncEngine I want to verify are being called...

// setup
var mockCrm = Mock.Of<ICrmProvider>(x => x.GetPickLists() == crmPickLists);
var mockCache = Mock.Of<ICacheProvider>(x => x.GetPickLists() == cachePickLists);
var mockLogger = Mock.Of<ILoggingProvider>();

// need to mock the following, not create a real class like this...
var syncEngine = new CustomerSyncEngine(mockLogger, mockCrm, mockCache);
Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
Andrew Connell
  • 4,939
  • 5
  • 30
  • 42
  • Can you provide a sample method you wish to verify being called? – Ciaran Jun 12 '12 at 14:32
  • 4
    So if I have dependencies on Classes rather than Interfaces I have to mock even theirs dependencies, this goes down recursively. In the end I'm force to use some interfaces to keep my code testable, even if I don't need the interfaces in my code. I think too many interfaces is a bigger smell than mocking concrete classes ... – Tarion Feb 23 '13 at 17:50

3 Answers3

112

Change the last line to

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;

and it should work

Der_Meister
  • 4,771
  • 2
  • 46
  • 53
Suhas
  • 7,919
  • 5
  • 34
  • 54
  • 5
    Not sure how this comment applies to my answer? – Suhas May 01 '13 at 20:24
  • 2
    Because this would cause a compile error as mockLogger and others will throw an exception that they do not have an Object property – Justin Pihony May 01 '13 at 20:30
  • 2
    Because the OP is using Mock.Of() to create mocks of the logger, crm, and cache types, the object returned is returned as T, not as Mock. So, mockLogger.Object etc. is not needed when giving them to the Mock of CustomerSyncEngine and as @JustinPihony mentioned, should show you a design time error. – Josh Gust Feb 08 '18 at 18:08
  • 1
    @suhas Shouldn't his be `new Mock(new object[]{mockLogger, mockCrm, mockCache}).Object;` – GiriB Mar 29 '19 at 09:48
  • 2
    @GiriB not needed, but possible, as the mock is defined with Params. public Mock(params object[] args) – Jiří Herník Jan 22 '20 at 16:14
  • 1
    I believe this answer is incorrect. It should be `var syncEngine = new Mock(mockLogger.Object, mockCrm.Object, mockCache.Object).Object;` You should be passing the objects that are being mocked to the constructor, not the mocks themselves. TLDR; Use the `Object` property on the mocks. – Dave Black Jan 20 '23 at 19:14
39

The last line is giving you a real instance because you are using the new keyword, not mocking CustomerSyncEngine.

You should use Mock.Of<CustomerSyncEngine>()

The only problem with Mocking Concrete types is that Moq would need a public default constructor(with no parameters) OR you need to create the Moq with constructor arg specification. http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

The best thing to do would be right click on your class and choose Extract interface.

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
Raghu
  • 2,678
  • 2
  • 31
  • 38
  • 4
    In regards to the problem, an alternative is to use an AutoMocking container. My favorite is Machine.Fakes in conjunction with Machine.Specifications, using an automocking container makes it easier to test smaller surface areas. Suppose Andrew needed to test a method in `CustomerSyncEngine` that only uses `ICrmProvider` with traditional mocking implementations must be provided for all 3 interfaces whereas an autmocking container would allow you to only provide one. – Chris Marisic Oct 14 '14 at 19:24
0

It should be: var syncEngine = new Mock<CustomerSyncEngine>(mockLogger.Object, mockCrm.Object, mockCache.Object).Object;

You should be passing the objects that are being mocked to the constructor, not the mocks themselves. TLDR; Use the Object property on the mocks.

Dave Black
  • 7,305
  • 2
  • 52
  • 41