जब मैं IHttpActionResult देता है तो मैं वेब एपी एक्शन विधि का परीक्षण कैसे कर सकता हूं?


135

मान लेते हैं कि यह मेरी क्रिया पद्धति है

public IHttpActionResult Get(int id)
{
    var status = GetSomething(id);
    if (status)
    {
        return Ok();
    }
    else
    {
        return NotFound();
    }
}

टेस्ट होगा

var httpActionResult = controller.Get(1);

मैं इसके बाद अपना http स्टेटस कोड कैसे जांचूं?


आप यहाँ एक नज़र डालनी चाहिए weblogs.asp.net/shijuvarghese/archive/2013/07/30/...
Fals

4
@ जिस साइट से आपने लिंक किया है वह वेब एप 1 का उपयोग करती है और ओपी के सवाल का प्रासंगिक जवाब नहीं है
डेविड पेडन

जवाबों:


190

यहां Ok()केवल उस प्रकार के लिए एक सहायक है OkResultजो प्रतिक्रिया की स्थिति निर्धारित करता है HttpStatusCode.Ok... इसलिए आप बस यह देख सकते हैं कि आपके एक्शन परिणाम का OkResultउदाहरण एक है ... कुछ उदाहरण (लिखित XUnit):

// if your action returns: NotFound()
IHttpActionResult actionResult = valuesController.Get(10);
Assert.IsType<NotFoundResult>(actionResult);

// if your action returns: Ok()
actionResult = valuesController.Get(11);
Assert.IsType<OkResult>(actionResult);

// if your action was returning data in the body like: Ok<string>("data: 12")
actionResult = valuesController.Get(12);
OkNegotiatedContentResult<string> conNegResult = Assert.IsType<OkNegotiatedContentResult<string>>(actionResult);
Assert.Equal("data: 12", conNegResult.Content);

// if your action was returning data in the body like: Content<string>(HttpStatusCode.Accepted, "some updated data");
actionResult = valuesController.Get(13);
NegotiatedContentResult<string> negResult = Assert.IsType<NegotiatedContentResult<string>>(actionResult);
Assert.Equal(HttpStatusCode.Accepted, negResult.StatusCode);
Assert.Equal("some updated data", negResult.Content);

66
MSTest मेंAssert.IsInstanceOfType(httpActionResult, typeof(OkResult));
सुनील

2
इसके अलावा, के लिए Created<T>(url,content)अपनेCreatedNegotiatedContentResult
सुनील

1
धन्यवाद सुनील..एक ऑपरेशन के Createdलिए अच्छा उदाहरण नहीं था Get... मैंने स्टेटस कोड को अब अलग-अलग कर दिया ...
किरण चल्ला

4
@StanimirYakimov परिणाम प्रकार हो जाएगा OkNegotiatedContentResult<T>जब आप प्रकार का ऑब्जेक्ट पारित Tकरने के लिएOk()
brianestey

2
IHttpStatusCodes के साथ कोई मदद जो अनियमित कोड लौटाती है? 422 की तरह? return new StatusCodeResult((HttpStatusCode)422, this);
रोबोकोजो

28

एक मृत प्रश्न को पुनर्जीवित करने का समय

वर्तमान उत्तर सभी प्रतिक्रियाशील वस्तु को एक ज्ञात प्रकार के कास्टिंग पर निर्भर करते हैं। दुर्भाग्य से, प्रतिक्रियाओं को नियंत्रक कार्यान्वयन के अंतरंग ज्ञान के बिना काम करने के लिए एक प्रयोग करने योग्य पदानुक्रम या अंतर्निहित रूपांतरण पथ नहीं लगता है। निम्नलिखित को धयान मे रखते हुए:

public class MixedCodeStandardController : ApiController {

    public readonly object _data = new Object();

    public IHttpActionResult Get() {
        return Ok(_data);
    }

    public IHttpActionResult Get(int id) {
        return Content(HttpStatusCode.Success, _data);
    }
}

कक्षा का परीक्षण:

var testController = new MixedCodeStandardController();

var getResult = testController.Get();
var posRes = getResult as OkNegotiatedContentResult<object>;
Assert.IsType<OkNegotiatedContentResult<object>>(getResult);
Assert.AreEqual(HttpStatusCode.Success, posRes.StatusCode);
Assert.AreEqual(testController._data, posRes.Content);

var idResult = testController.Get(1);
var oddRes = getResult as OkNegotiatedContentResult<object>; // oddRes is null
Assert.IsType<OkNegotiatedContentResult<object>>(idResult); // throws failed assertion
Assert.AreEqual(HttpStatusCode.Success, oddRes.StatusCode); // throws for null ref
Assert.AreEqual(testController._data, oddRes.Content); // throws for null ref

ब्लैक बॉक्स के बाहर से, प्रतिक्रिया स्ट्रीम अनिवार्य रूप से समान है। परीक्षण को यह पता होना चाहिए कि नियंत्रक ने इस तरह से परीक्षण करने के लिए रिटर्न कॉल कैसे लागू किया।

इसके बजाय, IHttpActionResult से HttpResponseMessage ऑब्जेक्ट का उपयोग करें। यह सुनिश्चित करता है कि परीक्षण सुसंगत हो सकता है, तब भी जब नियंत्रक कोड नहीं हो सकता है:

var testController = new MixedCodeStandardController();

var getResult = testController.Get();
var getResponse = getResult.ExecuteAsync(CancellationToken.None).Result;
Assert.IsTrue(getResponse.IsSuccessStatusCode);
Assert.AreEqual(HttpStatusCode.Success, getResponse.StatusCode);

var idResult = testController.Get(1);
var idResponse = idResult.ExecuteAsync(CancellationToken.None).Result;
Assert.IsTrue(idResponse.IsSuccessStatusCode);
Assert.AreEqual(HttpStatusCode.Success, idResponse.StatusCode);

3
इस काम को करने के लिए मुझे एक चीज करनी थी (IHttpActionResult.ExecuteAsync विधि का उपयोग करके) ApiController.Request विशेषता को निम्न के लिए सेट करना था:new HttpRequestMessage() {Properties = { { HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration() } }}
1818 को tobypls

16

यह किरण चल्ला द्वारा स्वीकार किया गया उत्तर है, जो NUnit के लिए अनुकूलित है;

var valuesController = controller;
// if your action returns: NotFound()
IHttpActionResult actionResult = valuesController.Get(10);
var notFoundRes = actionResult as NotFoundResult;
Assert.IsNotNull(notFoundRes);

// if your action returns: Ok()
actionResult = valuesController.Get(11);
var posRes = actionResult as OkResult;
Assert.IsNotNull(posRes);

// if your action was returning data in the body like: Ok<string>("data: 12")
actionResult = valuesController.Get(12);
var conNegResult = actionResult as OkNegotiatedContentResult<string>;
Assert.IsNotNull(conNegResult);
Assert.AreEqual("data: 12", conNegResult.Content);

// if your action was returning data in the body like: Content<string>(HttpStatusCode.Accepted, "some updated data");
actionResult = valuesController.Get(13);
var negResult = actionResult as NegotiatedContentResult<string>;
Assert.IsNotNull(negResult);
Assert.AreEqual(HttpStatusCode.Accepted, negResult.StatusCode);
Assert.AreEqual("some updated data", negResult.Content);


2

यदि IHttpActionResult में JSON ऑब्जेक्ट है, जैसे {"token": "A"}, तो हम निम्नलिखित कोड का उपयोग कर सकते हैं।

        var result = usercontroller.GetLogin("user", "password");
        Assert.IsInstanceOfType(result, typeof(OkNegotiatedContentResult<Dictionary<string,string>>));
        var content = result as OkNegotiatedContentResult<Dictionary<string, string> >;
        Assert.AreEqual("A", content.Content["token"]);

2

कुछ घंटों के शोध और प्रयास के बाद, मुझे अंत में पता चला कि अपने वेब एपीआई 2 विधियों का पूरी तरह से परीक्षण कैसे IHttpActionResultकरें जो OWIN मिडलवेयर और ASP.NET पहचान के डिफ़ॉल्ट कार्यान्वयन का उपयोग करते हैं।

मैं Get()निम्नलिखित विधि का परीक्षण करूंगा ApiController:

public class AccountController : ApiController
{
    private ApplicationUserManager _userManager;
    public ApplicationUserManager UserManager => _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();

    [Route("api/account"), HttpGet]
    public async Task<IHttpActionResult> Get()
    {
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user == null)
        {
            ModelState.AddModelError(ModelStateConstants.Errors, "Account not found! Try logging out and in again.");
            return BadRequest(ModelState);
        }

        var roles = await UserManager.GetRolesAsync(user.Id);

        var accountModel = new AccountViewModel
        {
            FullName = user.FullName,
            Email = user.Email,
            Phone = user.PhoneNumber,
            Organization = user.Organization.Name,
            Role = string.Join(", ", roles)
        };

        return Ok(accountModel);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_userManager != null)
            {
                _userManager.Dispose();
                _userManager = null;
            }
        }

        base.Dispose(disposing);
    }
}

एक बेस क्लास से शुरू करें जो सभी टेस्ट क्लास से इनहेरिट करेगा:

public class BaseTest
{
    protected static User CurrentUser;
    protected static IList<string> Roles;

    public BaseTest()
    {
        var email = "unit@test.com";

        CurrentUser = new User
        {
            FullName = "Unit Tester",
            Email = email,
            UserName = email,
            PhoneNumber = "123456",
            Organization = new Organization
            {
                Name = "Test Organization"
            }
        };

        Roles = new List<string>
        {
            "Administrator"
        };
    }

    protected void InitializeApiController(ApiController apiController)
    {
        //Init fake controller Http and Identity data
        var config = new HttpConfiguration();
        var request = new HttpRequestMessage();
        var routeData = new HttpRouteData(new HttpRoute(""));
        apiController.ControllerContext = new HttpControllerContext(config, routeData, request)
        {
            Configuration = config
        };

        apiController.User = new GenericPrincipal(new GenericIdentity(""), new[] { "" });

        //Initialize Mocks
        var appUserMgrMock = GetMockedApplicationUserManager();
        var appSignInMgr = GetMockedApplicationSignInManager(appUserMgrMock);
        var appDbContext = GetMockedApplicationDbContext();

        //Configure HttpContext.Current.GetOwinContext to return mocks
        var owin = new OwinContext();
        owin.Set(appUserMgrMock.Object);
        owin.Set(appSignInMgr.Object);
        owin.Set(appDbContext.Object);

        HttpContext.Current = new HttpContext(new HttpRequest(null, "http://test.com", null), new HttpResponse(null));
        HttpContext.Current.Items["owin.Environment"] = owin.Environment;
    }

    private static Mock<ApplicationSignInManager> GetMockedApplicationSignInManager(Mock<ApplicationUserManager> appUserMgrMock)
    {
        var authMgr = new Mock<Microsoft.Owin.Security.IAuthenticationManager>();
        var appSignInMgr = new Mock<ApplicationSignInManager>(appUserMgrMock.Object, authMgr.Object);

        return appSignInMgr;
    }

    private Mock<ApplicationUserManager> GetMockedApplicationUserManager()
    {
        var userStore = new Mock<IUserStore<User>>();
        var appUserMgr = new Mock<ApplicationUserManager>(userStore.Object);
        appUserMgr.Setup(aum => aum.FindByIdAsync(It.IsAny<string>())).ReturnsAsync(CurrentUser);
        appUserMgr.Setup(aum => aum.GetRolesAsync(It.IsAny<string>())).ReturnsAsync(Roles);

        return appUserMgr;
    }

    private static Mock<ApplicationDbContext> GetMockedApplicationDbContext()
    {
        var dbContext = new Mock<ApplicationDbContext>();
        dbContext.Setup(dbc => dbc.Users).Returns(MockedUsersDbSet);

        return dbContext;
    }

    private static IDbSet<User> MockedUsersDbSet()
    {
        var users = new List<User>
        {
            CurrentUser,
            new User
            {
                FullName = "Testguy #1",
                Email = "test@guy1.com",
                UserName = "test@guy1.com",
                PhoneNumber = "123456",
                Organization = new Organization
                {
                    Name = "Test Organization"
                }
            }
        }.AsQueryable();

        var usersMock = new Mock<DbSet<User>>();
        usersMock.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
        usersMock.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
        usersMock.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
        usersMock.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator);

        return usersMock.Object;
    }
}

InitializeApiControllerविधि मांस और आलू में शामिल है।

अब हम इसके लिए अपने परीक्षण लिख सकते हैं AccountController:

public class AccountControllerTests : BaseTest
{
    private readonly AccountController _accountController;

    public AccountControllerTests()
    {
        _accountController = new AccountController();
        InitializeApiController(_accountController);
    }

    [Test]
    public async Task GetShouldReturnOk()
    {
        var result = await _accountController.Get();
        var response = await result.ExecuteAsync(CancellationToken.None);
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
    }
}

सब कुछ काम करने के लिए, आपको Microsoft.OWIN.*और Microsoft.AspNet.*पैकेजों का एक समूह स्थापित करना होगा, मैं packages.configयहाँ अपना पेस्ट करूँगा :

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Castle.Core" version="4.3.1" targetFramework="net472" />
  <package id="EntityFramework" version="6.2.0" targetFramework="net472" />
  <package id="Microsoft.AspNet.Identity.Core" version="2.2.2" targetFramework="net472" />
  <package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.2" targetFramework="net472" />
  <package id="Microsoft.AspNet.Identity.Owin" version="2.2.2" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.Owin" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.Cookies" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.OAuth" version="4.0.1" targetFramework="net472" />
  <package id="Moq" version="4.10.1" targetFramework="net472" />
  <package id="Newtonsoft.Json" version="12.0.1" targetFramework="net472" />
  <package id="NUnit" version="3.11.0" targetFramework="net472" />
  <package id="Owin" version="1.0" targetFramework="net472" />
  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" />
  <package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net472" />
</packages>

परीक्षण बहुत सरल है, लेकिन यह दर्शाता है कि सब कुछ काम करता है :-)

खुश परीक्षण!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.