Модульное тестирование контроллера Web API, авторизованного с помощью JWT - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь выполнить модульное тестирование под контроллером Web API.

    [IdentityBasicAuthentication]
    [Authorize]
    [HttpPost]
    public HttpResponseMessage GetOrderByQR([FromBody]string id)
    {
        try
        {
            var identity = HttpContext.Current.User.Identity as ClaimsIdentity;

            var user = UserManager().IdentifyToken(identity);

            _orderManager.CheckOrderQRFraud(id);

            return Request.CreateResponse(HttpStatusCode.OK, _orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, id));
        }
        catch (BusinessException ex)
        {
            return CreateRawStringResponse(HttpStatusCode.NotFound, ex.Message);
        }
    }

Но нижеприведенный метод теста выдает нулевое исключение на IdentifyToken(), поскольку текущего пользователя нет, я понимаю, что.

    [TestMethod]
    public void GetOrderByQR_Returns_OK_On_Successful_Request()
    {
        string orderID = "4B854B3D-397E-425F-AEAF-00F7B4110021";

        var testResponse = _orderController.GetOrderByQR(orderID);

        Assert.AreEqual(HttpStatusCode.OK, testResponse.StatusCode);
    }

Пока я искал ответ, я увидел, что решение заключается в том, чтобы высмеивать этот атрибут авторизации.Таким образом, хотя я установил этот пакет Moq , я не смог запустить такой же успешный тест, как я новичок в модульном тестировании.

Ниже приведен метод IdentityToken(), если вам нужно проверитьэто также.

    public User IdentifyToken(ClaimsIdentity identity)
    {
        string userEmail = "";
        string userPassword = "";

        if (identity != null)
        {
            IEnumerable<Claim> claims = identity.Claims;
            List<Claim> claimsArray = claims.ToList();
            string[] emailArray = claimsArray[0].ToString().Split(':');
            string emailValue = emailArray[2].ToString();
            userEmail = emailValue.Trim();
            string[] passwordArray = claimsArray[1].ToString().Split(':');
            string passwordValue = passwordArray[2].ToString();
            userPassword = passwordValue.Trim();
        }

        var user = base.GetSingleBy(x => x.Email == userEmail && x.Password == userPassword);

        return user;
    }

Как мне написать мой метод испытаний?Заранее благодарим!

Редактировать:

Экземпляры класса Manager приведены ниже.

public class OrderController : BaseController
{
    OrderManager _orderManager;

    public OrderController()
    {
        _orderManager = new OrderManager();
    }

    //Order Controllers
}

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Потратив еще один день, чтобы узнать больше о модульном тестировании, я обнаружил, что мне нужно рассматривать (тестировать другими словами) каждый метод отдельно. Если я не ошибаюсь, отсюда и название Unit Test.

Итак, во-первых, я проверяю этот UserManager().IdentifyToken(identity); мой метод, как показано ниже.

    [TestMethod]
    public void IdentifyToken_Returns_UserWM_On_Successful_Request()
    {
        UserManager userManager = new UserManager();

        MD5Hasher passwordHasher = new MD5Hasher();

        IEnumerable<Claim> claims = new List<Claim>
        {
            new Claim(ClaimTypes.Email, "creditmaster@admin.com"),
            new Claim(ClaimTypes.Hash, passwordHasher.Encrypt("qW12345?"))
        };

        ClaimsIdentity identity = new ClaimsIdentity();
        identity.AddClaims(claims);

        var testResult = userManager.IdentifyToken(identity);

        Assert.AreEqual(typeof(UserWM), testResult.GetType());
    }

Получив успешный тестовый ответ, я продолжаю с _orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, id));, как показано ниже.

    [TestMethod]
    public void GetSingleOrderWithUserPaymentAccountBy_Returns_OrderWM_On_Successful_Request()
    {
        Random rnd = new Random();
        int randomUser = rnd.Next(0, 690);
        int randomOrder = rnd.Next(0, 40);

        OrderManager orderManager = new OrderManager();
        UserManager userManager = new UserManager();

        List<UserWM> userList = userManager.GetAllUser();
        var user = userList[randomUser];

        List<OrderWM> orderList = orderManager.GetAllOrder();
        var order = orderList[randomOrder];
        string orderCode = "HHBI5OBFWG5WDSKP";

        var testResult = orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, orderCode);

        Assert.AreEqual(typeof(OrderWM), testResult.GetType());
    }

В конце концов, если вы сможете успешно выполнить модульное тестирование всех ваших методов по отдельности, тогда они будут успешно работать при одновременном вызове ..

Я также хотел бы поделиться нижеприведенным методом тестирования, где я тестирую модульно свой метод (имя - InsertUser), который вставляет пользователей в базу данных после того, как все обязательные свойства, связанные с сущностью пользователя, заполнены, как предполагалось.

Сложность в том, что InsertUser содержит слишком много if-else элементов управления проверкой, например,

        if (string.IsNullOrEmpty(user.FirstName))
        {
            throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserFirstnameEmptyError), "");
        }

Так как здесь слишком много строк кода, я не хочу, чтобы вы терялись вокруг них, поэтому не разделяли все Insert User.

Если вы также сталкивались с подобным случаем в своих модульных тестах, единственное, что вам нужно сделать, это собрать эти проверки в другой метод (я назвал его InsertUserValidation). Итак, теперь у нас есть два разных метода: InsertUser и InsertUserValidation.

Теперь, возможно, вы спрашиваете, почему мы должны отделять валидации от основного метода. В моем случае у меня есть зависящие от времени проверки, как показано ниже.

        if (activationRequest == null)
        {
            throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeNotRequested), "");
        }
        else if (activationRequest.CreationTime.AddMinutes(3) < DateTime.Now)
        {
            throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeIsTimedOut), "");
        }

Подумайте об этом, поскольку промежуток времени между двумя Unit Test неясен, вам необходимо поместить проверки такого рода в другой метод, чтобы их можно было смоделировать, как описано в методе тестирования ниже. Например, возможно, я запускаю свой связанный метод, который создает это activationRequest пять минут назад, и сейчас я запускаю свой метод InsertUser. Если бы я не отделил эту проверку, InsertUser все равно содержал бы эту проверку выше, и он вызовет исключение, так как при вызове он уже более трех минут.

    [TestMethod]
    public void InsertUser_Returns_UserWM_On_Successful_Request()
    {
        UserManager userManager = new UserManager();

        MD5Hasher passwordHasher = new MD5Hasher();

        Random rnd = new Random();
        int dummyEmailName = rnd.Next(0, 700);
        string dummyEmail = dummyEmailName.ToString() + "@gmail.com";

        UserActivationRequest userActivationRequest = new UserActivationRequest
        {
            EMail = dummyEmail,
            ActivationCode = "444855",
            IsUsed = false,
            IsActive = true,
            ConfirmationType = 1,
            ReadCount = 0
        };

        UserCreateAccountWM userCreateAccountWM = new UserCreateAccountWM()
        {
            FirstName = "Unit",
            LastName = "Test",
            Email = dummyEmail,
            Password = passwordHasher.Encrypt("yC123456?"),
            CountryID = 1,
            PhoneCountryCode = 90,
            MobileNumber = "5327894512",
            ActivationCode = "444855"
        };

        var validationMock = new Mock<UserManager>();
        validationMock.CallBase = true;
        validationMock.Setup(x => x.InsertUserValidation(It.IsAny<UserCreateAccountWM>())).Returns(userActivationRequest); //if your validations do not return anything back, just forget about the part with .Returns()

        var testResult = validationMock.Object.InsertUser(userCreateAccountWM);

        Assert.AreEqual(typeof(UserWM), testResult.GetType());
    }

Да, если я не ошибаюсь, вам все равно нужно создать связанные сущности.

Прежде чем я закончу, я использовал Moq Framework, и не забывайте, что методы, которые вы разделяете, должны быть в том же пространстве имен.

Надеюсь, я буду полезен тем, кто новичок во всем этом.

0 голосов
/ 18 сентября 2018

вы можете использовать TestServer для проверки ваших методов API

 using (var server = TestServer.Create<Startup>())
    {
        var result = await server.HttpClient.GetAsync("api/Orders/id");
        string responseContent = await result.Content.ReadAsStringAsync();
        var entity = JsonConvert.DeserializeObject<List<Orders>>(responseContent);
        // other code
    }
...