我不确定如何解决此问题,尝试对方法“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);
}
答案 0 :(得分:145)
为了控制模拟对象的行为(至少在Moq中),您需要模拟一个接口,或者确保您尝试控制的行为标记为虚拟。在你的评论中,我理解它,以便_mockArticleDao
的实例化完成如下:
_mockArticleDao = new Mock<ArticleDAO>();
如果您想这样做,则需要标记GetArticle
方法virtual
:
public class ArticleDAO : GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
public virtual IArticle GetByTitle(string title)
{
// ...
}
}
否则(这是我推荐的),请改为模拟界面。
_mockArticleDao = new Mock<IArticleDAO>();
答案 1 :(得分:0)
我在尝试从框架模拟无法控制的类时遇到了同样的问题。在我的特定情况下,我不得不模拟 HttpResponseMessage 来设置状态代码以返回Ok,但是如果该属性不是虚拟的,该怎么办呢?
此代码无效,因为 StatusCode 不是虚拟的:
var httpResponseMessage = new Mock<HttpResponseMessage>();
httpResponseMessage.SetupGet(x => x.StatusCode).Returns(HttpStatusCode.OK);
答案:
完成。现在,您可以模拟一个派生对象,该对象可以在使用原始对象的任何地方使用,因为它继承自它。这是我的 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);
答案 2 :(得分:0)
这是我模拟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测试都使用它,因为我可以传递状态,内容等。因此,我可以测试不同的返回值。