Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I get Moq to add attributes to the mock class?

Tags:

I'm writing a command-line interface to my project. The user enters "create project foo", and it finds the controller responsible for "project" and then invokes the Create method, passing "foo" as the first argument.

It relies heavily on attributes and reflection: the controller looks something like this:

[ControllerFor("project")] class ProjectController {     [ControllerAction("create")]     public object Create(string projectName) { /* ... */ } } 

I'd like to use Moq in the unit tests for the parser, something like this:

Mock<IProjectsController> controller = new Mock<IProjectsController>(); controller.Expect(f => f.Create("foo"));  parser.Register(controller.Object); parser.Execute("create project foo");  controller.VerifyAll(); 

Adding the attributes to the interface doesn't appear to work -- they're not inherited by derived classes.

Can I get Moq to add attributes to the class being mocked?

like image 422
Roger Lipscombe Avatar asked Feb 12 '09 09:02

Roger Lipscombe


People also ask

Can you mock a class with Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.

What can be mocked with Moq?

Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for .

How do you mock a method in Moq?

First, we instantiate the FakeDbArticleMock class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it. Finally, we call the method we are testing and assert the results.

How do you mock a class without an interface?

Simply mark any method you need to fake as virtual (and not private). Then you will be able to create a fake that can override the method. This leaves me wonder if it is necessary at all to create an interface for every class I want to mock.


1 Answers

Update: I've just realised that you can actually add attributes to an existing type by using TypeDescriptor.AddAttributes, which can be executed against an instance or a a type:

Mock<IRepository> repositoryMock = new Mock<IRepository>();  CustomAttribute attribute = new CustomAttribute();  // option #1: to the instance TypeDescriptor.AddAttributes(repositoryMock.Object, attribute );  // option #2: to the generated type TypeDescriptor.AddAttributes(repositoryMock.Object.GetType(), attributes); 

If you need it, AddAttribute returns a TypeDescriptorProvider that can be passed to TypeDescriptor.RemoveProvider to remove the attributes afterwards.

Be aware that Attribute.GetCustomAttributes will not find attributes added at runtime in this way. Instead, use TypeDescriptor.GetAttributes.

Original Answer

I don't belive Moq (or any other mocking framework for that matter) supports custom attributes. I do know that Castle Proxy (the framework commonly used to actually create the class) does support it, but there'd be no way to access it through Moq.

Your best bet is to abstract your method of loading Attributes into an interface (that accepts the Type and the Attribute type) and then mock that.

Edit: For example:

public interface IAttributeStrategy {     Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit);     Attribute[] GetAttributes(Type owner, bool inherit); }  public class DefaultAttributeStrategy : IAttributeStrategy {     public Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit)     {         return owner.GetCustomAttributes(attributeType, inherit);     }      public Attribute[] GetAttributes(Type owner, bool inherit)     {         return owner.GetCustomAttributes(inherit);     } } 

The class that needs the attributes uses an instance of IAttributeStrategy (either through an IoC container, or having it optionally passed into the constructor). Usually it will be a DefaultAttributeStrategy, but you can now mock IAttributeStrategy in order to override the output.

It might sound convoluted, but adding a layer of abstraction is much easier than attempting to trying to actually mock Attributes.

like image 137
Richard Szalay Avatar answered Oct 15 '22 13:10

Richard Szalay