Веб-службы тестирования устройств - HttpContext
Я хочу написать модульные тесты для веб-службы. Я создаю свой тестовый проект, ссылку на мой веб-проект (не ссылку на службу, ссылку на сборку), а затем написать код для тестирования веб-сервисов - они работают нормально. Однако есть некоторые службы, которые гарантируют, что пользователь выполнил вход в веб-приложение с помощью HttpContext.Current.User.Identity.IsAuthenticated
.
В контексте тестов нет такой вещи, как HttpContext, поэтому тесты всегда терпят неудачу. Как следует тестировать эти типы веб-сервисов?
Ответы
Ответ 1
Здесь - это связанное обсуждение.
Я перестал ссылаться на HttpContext.Current
напрямую. и вместо этого используйте этот класс:
public class HttpContextFactory
{
private static HttpContextBase m_context;
public static HttpContextBase Current
{
get
{
if (m_context != null)
return m_context;
if (HttpContext.Current == null)
throw new InvalidOperationException("HttpContext not available");
return new HttpContextWrapper(HttpContext.Current);
}
}
public static void SetCurrentContext(HttpContextBase context)
{
m_context = context;
}
}
и используйте HttpContextFactory.Current
вместо HttpContext.Current
в нашем коде.
Затем вы пишете это в своем тесте:
HttpContextFactory.SetCurrentContext(GetMockedHttpContext());
где GetMockedHttpContext() из здесь и выглядит следующим образом:
private System.Web.HttpContextBase GetMockedHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.Setup(ctx => ctx.User).Returns(user.Object);
user.Setup(x => x.Identity).Returns(identity.Object);
identity.Setup(id => id.IsAuthenticated).Returns(true);
identity.Setup(id => id.Name).Returns("test");
return context.Object;
}
Он использует mocking framework под названием moq
В вашем тестовом проекте вам нужно добавить ссылку на System.Web
и System.Web.Abstractions
, где HttpContextBase
определен.
Ответ 2
Если вы используете насмешку, вы можете обернуть эту логику в другом классе:
interface IAuthenticator
{
bool IsAuthenticated();
}
и реализовать реальный:
class Authenticator : IAuthenticator
{
bool IsAuthenticated()
{
return HttpContext.Current.User.Identity.IsAuthenticated;
}
}
но в тесте создайте mock и верните true или false:
Mock<IAuthenticator> mock = new Mock<IAuthenticator>();
mock.Expect(x => x.IsAuthenticated()).Returns(true);
Ответ 3
Вы можете подумать о зависимости от System.Web.Abstractions.HttpContextBase вместо использования HttpContext.Current. В сборке System.Web.Abstractions имеется множество обычных классов ASP.NET Http *, уже завернутых для вас. Они используются во всем коде ASP.NET MVC. Если вы используете инфраструктуру IoC/DI, она довольно проста в использовании. Например, в Ninject:
Bind<HttpContextBase>.ToMethod(x => new HttpContextWrapper(HttpContext.Current));
а затем в вашем конструкторе...
public class SomeWebService
{
private HttpContextBase _httpContext;
public SomeWebService(HttpContextBase httpContext)
{
_httpContext = httpContext;
}
public void SomeOperationNeedingAuthorization()
{
IIdentity userIdentity = _httpContext.User.Identity;
if (!userIdentity.IsAuthenticated)
return;
// Do something here...
}
}
Этот способ упрощен, но я надеюсь, что вы получите эту идею... Как упоминалось в Aliostad, вы можете легко высмеять HttpContextBase с помощью Rhino Mocks или Moq и т.д., чтобы протестировать SomeOperationNeedingAuthorization.
Ответ 4
В итоге я разместил свойство в веб-службе:
Private mIdentity As System.Security.Principal.IIdentity
Public Property Identity() As System.Security.Principal.IIdentity
Get
If mIdentity Is Nothing Then mIdentity = HttpContext.Current.User.Identity
Return mIdentity
End Get
Set(ByVal value As System.Security.Principal.IIdentity)
mIdentity = value
End Set
End Property
Затем в моем методе веб-службы:
<WebMethod()> _
Public Function GetProject(ByVal projectId As Int32) As String
If Me.Identity.IsAuthenticated Then
'code here
End If
End Function
Затем в моем тесте (я использую RhinoMocks):
Dim mockery As New MockRepository()
Dim mockIdentity As System.Security.Principal.IIdentity = mockery.DynamicMock(Of System.Security.Principal.IIdentity)()
Dim projectService As New TeamDynamix.Enterprise.Web.Next.ProjectService()
projectService.Identity = mockIdentity
mockIdentity.Stub(Function(i As System.Security.Principal.IIdentity) i.IsAuthenticated).Return(True)
Ответ 5
Основываясь на вышеприведенном решении, я реализовал класс-оболочку в платформе O2, который позволяет легко использовать эти издевательские классы, для Например, это то, как я могу писать и читать из HttpRequest.InputStream
var mockHttpContext = new API_Moq_HttpContext();
var httpContext = mockHttpContext.httpContext();
httpContext.request_Write("<html><body>".line());
httpContext.request_Write(" this is a web page".line());
httpContext.request_Write("</body></html>");
return httpContext.request_Read();
см. эту запись в блоге для более подробной информации: http://o2platform.wordpress.com/2011/04/05/mocking-httpcontext-httprequest-and-httpresponse-for-unittests-using-moq/