起订量:不可覆盖成员上的设置无效:x => x.GetByTitle(“asdf”)

发布于 2024-08-16 05:57:30 字数 1262 浏览 4 评论 0原文

不知道如何解决这个问题,尝试对方法“GetByTitle”进行单元测试

以下是我的定义:

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);
}

单元测试:

[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);
}

运行测试给出错误:

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

更新

我的[Setup ] 看起来像:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}

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);    
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ゞ花落谁相伴 2024-08-23 05:57:31

为了控制模拟对象的行为(至少在 Moq 中),您需要模拟一个接口,或者确保您尝试控制的行为被标记为虚拟。在您的评论中,我的理解是 _mockArticleDao 的实例化是这样完成的:

_mockArticleDao = new Mock<ArticleDAO>();

如果您想保持原样,则需要标记 GetArticle 方法 < code>virtual:

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

否则(这是我推荐的),请改为模拟接口。

_mockArticleDao = new Mock<IArticleDAO>();

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>();
情深已缘浅 2024-08-23 05:57:31

创建一个继承的可模拟类

我在尝试从框架模拟一个我无法控制的类时遇到了同样的问题。在我的具体情况下,我必须模拟 HttpResponseMessage 设置状态代码以返回“Ok”,但如果该属性不是虚拟的,该怎么办?

此代码不起作用,因为 StatusCode 不是虚拟的:

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

答案

  1. 在测试项目中创建一个新类,继承自要模拟的类
  2. 重新定义同一组构造函数调用基构造函数
  3. 重新定义要设置为虚拟的非虚拟属性或方法(使用 new 关键字显式隐藏原始成员)
  4. 从重新定义的虚拟属性或方法中,调用非虚拟基属性或方法。

完毕。现在,您可以模拟一个派生对象,该对象可以在使用原始对象的任何地方使用,因为它继承自原始对象。这是我的 MockableHttpResponseMessage 类的代码:

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; }
    }        
}

现在,此代码可以工作:

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

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);
二智少女 2024-08-23 05:57:31

下面是我Mock HttpMessageHandler的方法:

private HttpRequestMessage requestMessage = new HttpRequestMessage();
Mock<HttpMessageHandler> handlerMock = 
GetHttpMessageHandlerMock(HttpStatusCode.OK);  

MyRestService myRestService = new MyRestService();
myRestService.client = new HttpClient(handlerMock.Object);

var response = myRestService.Get("");

//此时,调用了HttpRequestMessage的Mock,并且Callback填充了我的类变量requestMessage。我现在可以查看 requestMessage 的内部。

var headers = requestMessage?.Headers.ToString();
var queryBegin = requestMessage.RequestUri.OriginalString.IndexOf('?');
var queryString = requestMessage.RequestUri.OriginalString.Substring(queryBegin + 1);
        Assert.That(headers.Contains("x-api-key: fakeApiKey"));

//下面的帮助方法

private Mock<HttpMessageHandler> GetHttpMessageHandlerMock(HttpStatusCode statusCode)
{
        var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
        handlerMock
           .Protected()
           .Setup<Task<HttpResponseMessage>>(
              "SendAsync",
              ItExpr.IsAny<HttpRequestMessage>()
             , ItExpr.IsAny<CancellationToken>()
           )
           .Returns(Task.FromResult(GetFakeResponse(statusCode)))
           .Callback<HttpRequestMessage, CancellationToken>((p, q) => requestMessage = p)
          .Verifiable();
        return handlerMock;
    }


    private HttpResponseMessage GetFakeResponse(HttpStatusCode statusCode)
    {
        var s = "{\"data\":{\"status\":\"SUCCESS\",\"errorCode\":\"\",\"errorMessage\":\"9\"}}";
        HttpResponseMessage response = new HttpResponseMessage()
        {

            StatusCode = statusCode,
            Content = new StringContent(s),
            ReasonPhrase = "OK",
            RequestMessage = new HttpRequestMessage()
        };
        return response;
    }

我几乎将其用于所有 REST 测试,因为我可以传入状态、内容等。因此,我可以测试不同的返回值。

Here's how I Mock HttpMessageHandler:

private HttpRequestMessage requestMessage = new HttpRequestMessage();
Mock<HttpMessageHandler> handlerMock = 
GetHttpMessageHandlerMock(HttpStatusCode.OK);  

MyRestService myRestService = new MyRestService();
myRestService.client = new HttpClient(handlerMock.Object);

var response = myRestService.Get("");

//At this point, the Mock of HttpRequestMessage is called and the Callback fills my class variable requestMessage. I can now look inside the requestMessage.

var headers = requestMessage?.Headers.ToString();
var queryBegin = requestMessage.RequestUri.OriginalString.IndexOf('?');
var queryString = requestMessage.RequestUri.OriginalString.Substring(queryBegin + 1);
        Assert.That(headers.Contains("x-api-key: fakeApiKey"));

//Helper methods below

private Mock<HttpMessageHandler> GetHttpMessageHandlerMock(HttpStatusCode statusCode)
{
        var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
        handlerMock
           .Protected()
           .Setup<Task<HttpResponseMessage>>(
              "SendAsync",
              ItExpr.IsAny<HttpRequestMessage>()
             , ItExpr.IsAny<CancellationToken>()
           )
           .Returns(Task.FromResult(GetFakeResponse(statusCode)))
           .Callback<HttpRequestMessage, CancellationToken>((p, q) => requestMessage = p)
          .Verifiable();
        return handlerMock;
    }


    private HttpResponseMessage GetFakeResponse(HttpStatusCode statusCode)
    {
        var s = "{\"data\":{\"status\":\"SUCCESS\",\"errorCode\":\"\",\"errorMessage\":\"9\"}}";
        HttpResponseMessage response = new HttpResponseMessage()
        {

            StatusCode = statusCode,
            Content = new StringContent(s),
            ReasonPhrase = "OK",
            RequestMessage = new HttpRequestMessage()
        };
        return response;
    }

I use this for almost all my REST tests, because I can pass in status, content, etc. So, I can test different return values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文