Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq: Invalid setup on a non-overridable member: x => x.GetByTitle("asdf")

Not sure how I can fix this, trying to do a unit test on the method "GetByTitle"

Here are my definitions:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public IArticle GetByTitle(string title)
    {
        IQuery query = Session.CreateQuery("...")
        return query.UniqueResult<IArticle>();
    }
}

public interface IArticleDAO
{
    IArticle GetByTitle(string title);
}

unit test:

[Test]
public void can_load_by_title()
{
    _mockDaoFactory.Setup(x => x.GetArticleDao())
                                .Returns(_mockArticleDao.Object);
    _mockArticleDao.Setup(x => x.GetByTitle("some title"))
                                .Returns(article1.Object);

    _articleManager.LoadArticle("some title");

    Assert.IsNotNull(_articleManager.Article);
}

Running the test gives me the error:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetByTitle("some title")

Update

My [Setup] looks like:

[Setup]
public void SetUp()
{
     _mockDaoFactory = new Mock<IDaoFactory>();
     _mockArticleDao = new Mock<ArticleDao>();

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}
like image 904
mrblah Avatar asked Dec 25 '09 21:12

mrblah


2 Answers

In order to control the behavior of a mock object (in Moq, at least), you either need to mock an interface, or make sure that the behavior you're trying to control is marked virtual. In your comment, I understand it so that the instantiating of _mockArticleDao is done something like this:

_mockArticleDao = new Mock<ArticleDAO>();

If you want to keep it as so, you need to mark the GetArticle method virtual:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public virtual IArticle GetByTitle(string title)
    {
        // ...
    }
}

Otherwise (and this is what I recommend), mock the interface instead.

_mockArticleDao = new Mock<IArticleDAO>();
like image 82
Tomas Aschan Avatar answered Oct 01 '22 12:10

Tomas Aschan


Create an inherited mockable class

I had the same issue trying to mock a class I have no control over, from a framework. In my specific case I had to mock an HttpResponseMessage setting up the status code to return Ok, but how to do it if that property is not virtual?

This code does not work because StatusCode is not virtual:

var httpResponseMessage = new Mock<HttpResponseMessage>();
httpResponseMessage.SetupGet(x => x.StatusCode).Returns(HttpStatusCode.OK);

Answer:

  1. Create a new class in your test project, inheriting from the class you want to mock
  2. Redefine the same set of constructors calling the base constructors
  3. Redefine the non virtual properties or methods you want to setup as virtual (use the new keyword to explicitly hide the original members)
  4. From the redefined virtual properties or methods, call the non virtual base property or method.

Done. Now you can mock a derived object that can be used anywhere the original one is used, because it inherits from it. Here is the code for my MockableHttpResponseMessage class:

public class MockableHttpResponseMessage: HttpResponseMessage
{
    public MockableHttpResponseMessage() : base() {}
    public MockableHttpResponseMessage(HttpStatusCode code) : base (code) { }
    public new virtual HttpStatusCode StatusCode { 
        get { return base.StatusCode; } 
        set { base.StatusCode = value; }
    }        
}

Now, this code works:

var httpResponseMessage = new Mock<MockableHttpResponseMessage>();
httpResponseMessage.SetupGet(x => x.StatusCode).Returns(HttpStatusCode.OK);
like image 40
Marcelo Barsotti Avatar answered Sep 27 '22 12:09

Marcelo Barsotti