Формы тестирования интеграции с вложенными объектами - PullRequest
0 голосов
/ 04 ноября 2018

Я использую .NET Core с Boilerplate. Я пытаюсь провести модульное тестирование некоторых новых форм, которые требуют наличия вложенных объектов со свойствами. Интеграционные тесты используют AbpAspNetCoreIntegratedTestBase<Startup>, который использует экземпляры HttpClient и TestServer. Клиент имеет в своем распоряжении различные методы. Есть только методы GetAsync, PostAsync, SendSync и PutAsync.

Я думал, что освоил некоторые методы и вспомогательные методы в этой работе и до сих пор добился успеха. Тем не менее, у меня есть форма с моделью под названием Vendor, у Vendor модель адреса является частью модели представления. Это сделано для того, чтобы я мог повторно использовать модель представления адреса с другими элементами приложения, которые также требуют адрес (а).
Один из помощников, который используется с BoilerPlate: GetUrl<TController>(string actionName, object queryStringParamsAsAnonymousObject) Так как это сообщение из формы, которую я пытаюсь использовать public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content) Независимо от того, что я пытаюсь сделать, я получаю ответ 400 Bad Request и мой тест не пройден, прежде чем он попадет внутрь метода контроллера Я в недоумении, как справиться с этим.
Вот мои модели:

VendorViewModel:

[AutoMap(typeof(Domains.Vendor))]
public class VendorViewModel : BaseViewModelEntity
{
    [Required]
    public string Name { get; set; }
    [Required]
    public string PointOfContact { get; set; }
    [Required]
    public string Email { get; set; }
    [Required]
    public int AddressId { get; set; }
    //[Required]
    //public string Address1 { get; set; }
    //public string Address2 { get; set; }
    //public string Address3 { get; set; }
    //[Required]
    //public string City { get; set; }
    //[Required]
    //public int State { get; set; }
    //[Required]
    //public string Zip { get; set; }
    //[Required]
    //public string Phone { get; set; }
    //public string Fax { get; set; }
    public AddressViewModel VendorAddress { get; set; }


    public VendorViewModel()
    {
        VendorAddress = new AddressViewModel();
    }

    public VendorViewModel(VendorDto vendor)
    {
        Id = vendor.Id;
        Name = vendor.Name;
        IsActive = vendor.IsActive;
        PointOfContact = vendor.PointOfContact;
        Email = vendor.Email;
        AddressId = vendor.AddressId;
        CreatorUserId = vendor.CreatorUserId;
        CreationTime = vendor.CreationTime;
        DeleterUserId = vendor.DeleterUserId;
        DeletionTime = vendor.DeletionTime;
        LastModificationTime = vendor.LastModificationTime;
        LastModifierUserId = vendor.LastModifierUserId;
        //Address1 = vendor.Address.Address1;
        //Address2 = vendor.Address.Address2;
        //Address3 = vendor.Address.Address3;
        //City = vendor.Address.City;
        //State = vendor.Address.State;
        //Zip = vendor.Address.Zip;
        //Phone = vendor.Address.Phone;
        //Fax = municipalities.Address.Fax;
       VendorAddress = new AddressViewModel()
        {
            Id = vendor.Address.Id,
            Address1 = vendor.Address.Address1,
            Address2 = vendor.Address.Address2,
            Address3 = vendor.Address.Address3,
            City = vendor.Address.City,
            State = vendor.Address.State,
            Zip = vendor.Address.Zip,
            Phone = vendor.Address.Phone,
            Fax = vendor.Address.Fax,
            CreationTime = vendor.Address.CreationTime,


        };


    }
}

Модель просмотра адреса:

public class AddressViewModel : BaseViewModelEntity
{
    [Required]
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    [Required]
    public string City { get; set; }
    [Required]
    public int State { get; set; }
    [Required]
    public string Zip { get; set; }
    [Required]
    public string Phone { get; set; }
    public string Fax { get; set; }

    public AddressViewModel()
    {

    }

    public AddressViewModel(AddressDto address)
    {
        Id = address.Id;
        Address1 = address.Address1;
        Address2 = address.Address2;
        Address3 = address.Address3;
        City = address.City;
        State = address.State;
        Zip = address.Zip;
        Phone = address.Phone;
        Fax = address.Phone;
        CreatorUserId = address.CreatorUserId;
        CreationTime = address.CreationTime;
        DeleterUserId = address.DeleterUserId;
        DeletionTime = address.DeletionTime;
        LastModificationTime = address.LastModificationTime;
        LastModifierUserId = address.LastModifierUserId;
   }
 }

Мой тест настроен с помощью xUnit

//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
        Client.DefaultRequestHeaders.Add("my-name", "admin");
        Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data
        var addressViewModel = new AddressViewModel()
        {
            Address1 = "123 This Way", City = "Arlington", State = 44, Zip = "76001", Phone = "8175555555",
            CreationTime = DateTime.Now
        };

        var viewModelSave = new VenderViewModel()
        {
            Name = "Controller Test Name",
            PointOfContact = "Tom Jerry",
            Email = "Tom.Jerry@yolo.com",
            CreationTime = DateTime.Now,
            LastModificationTime = null,
            IsActive = true,
            AddressId = 0,
            VendorAddress = addressViewModel
            //Address1 = "123 This Way",
            //City = "Arlington",
            //State = 44,
            //Zip = "76001",
            //Phone = "8175555555"
        };
/* This is an attempt to use string interpolation to create querystring parameters */
        //var rawData =
        //    $"?Name={viewModelSave.Name}&Id={viewModelSave.Id}&PointOfContat=${viewModelSave.PointOfContact}&Email={viewModelSave.Email}&CreationTime={DateTime.Now}" +
        //    $"&LastModificationTime=&IsActive={viewModelSave.IsActive}&AddressId={viewModelSave.AddressId}&VendorAddress.Id={viewModelSave.VendorAddress.Id}&VendorAddress.Address1={viewModelSave.VendorAddress.Address1}" +
        //    $"&VendorAddress.City={viewModelSave.VendorAddress.City}&VendorAddress.State={viewModelSave.VendorAddress.State}&VendorAddress.Zip={viewModelSave.VendorAddress.Zip}&VendorAddress.Phone={viewModelSave.VendorAddress.Phone}" +
        //    $"&VendorAddress.CreationTime={DateTime.Now}&VendorAddress.IsActive={viewModelSave.VendorAddress.IsActive}";

/*This is an attempt to create a json object that could be serialize into an object as the "queryStringParamsAsAnonymousObject" that can be used in the GetUrl Helper method below */

        var rawData = $"{{'Name':'Controller Test Name','PointOfContact':'Tom Jerry', 'Email': 'Tom.Jerry@yolo.com',"
                       + "'CreationTime':'" +  DateTime.Now + "','LastModificationTime':'','IsActive' : 'true','AddressId':'0','Address.Address1':'123 This Way',"
                       + "'Address.City':'Arlington','Address.State':'44','Address.Zip':'76001','Address.Phone':'8175555556','Address.IsActive':'true'}";

        var jsonData = JsonConvert.DeserializeObject(rawData);

       //Serialize ViewModel to send with Post as part of the HttpContent object 
        var data = JsonConvert.SerializeObject(viewModelSave);


        var vendorAddress = new
        {
            viewModelSave.vendorAddress.Id,
            viewModelSave.vendorAddress.Address1,
            viewModelSave.vendorAddress.City,
            viewModelSave.vendorAddress.State,
            viewModelSave.vendorAddress.Zip,
            viewModelSave.vendorAddress.Phone,
            viewModelSave.vendorAddress.IsActive,
            viewModelSave.vendorAddress.CreationTime
        };

        //actually get the url from helper method (with various attempts at creating an anonymousObject directly
        var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor),
    new
    {
        viewModelSave.Id,
        viewModelSave.Name,
        viewModelSave.PointOfContact,
        viewModelSave.Email,
        viewModelSave.CreationTime,
        viewModelSave.LastModificationTime,
        viewModelSave.IsActive,
        viewModelSave.AddressId,
        vendorAddress
        //VendorAddress_Address1 = vendorAddress.Address1,
        //VendorAddress_Id = vendorAddress.Id,
        //VendorAddress_City = vendorAddress.City,
        //VendorAddress_State = vendorAddress.State,
        //VendorAddress_Zip = vendorAddress.Zip,
        //VendorAddress_Phone = vendorAddress.Phone,
        //VendorAddress_IsActive = vendorAddress.IsActive,
        //VendorAddress = new 
        //{
        //    viewModelSave.VendorAddress.Id,
        //    viewModelSave.VendorAddress.Address1,
        //    viewModelSave.VendorAddress.City,
        //    viewModelSave.VendorAddress.State,
        //    viewModelSave.VendorAddress.Zip,
        //    viewModelSave.VendorAddress.Phone,
        //    viewModelSave.VendorAddress.IsActive,
        //    viewModelSave.VendorAddress.CreationTime
        //},
        //viewModelSave.Address1,
        //viewModelSave.City,
        //viewModelSave.State,
        //viewModelSave.Zip,
        //viewModelSave.Phone
    }

    );
        var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
        var message = new HttpRequestMessage {
            Content = content,
            Method = HttpMethod.Post,
            RequestUri = new Uri("http://localHost" + url)

            };

        //Act
        var response = await PostResponseAsObjectAsync<AjaxResponse>(url, content);

        //Assert
        var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });

        response.ShouldBeOfType<AjaxResponse>();
        response.Result.ShouldNotBeNull();
        count.ShouldBe(3);
    }

Пока я пытаюсь отладить происходящее. Я заметил, что свойства VendorAddress, которые отправляются через тестовый запрос, не соответствуют тому, как выглядит фактическая публикация формы при анализе в инструментах разработчика Chrome. В Chrome я вижу (пример: PointOfContact: «Том Джерри» IsActive: Правда VendorAddress.Address1: "123 This Way" VendorAddress.City: "Арлингтон") Я не могу перенести свои тестовые данные в тот же формат, поэтому они не связываются правильно с моими моделями представления на посту, и, таким образом, возвращают ответ 400 и не проходят тест.

Я заставил его работать, если я удаляю модель представления адреса все вместе и помещаю эти свойства как свойства VendorViewModel. Тем не менее, я столкнулся бы с той же, если не похожей проблемой, если я пытаюсь сохранить коллекцию объектов вместе с моделью основного вида. Я чувствую, что должен быть способ представить данные тестовых форм через интеграционные тесты с образцом. Мне просто нужна недостающая часть этой загадки.

1 Ответ

0 голосов
/ 07 ноября 2018

Решение, которое работает как для отправки, так и для отправки запросов: .NET Core имеет класс QueryHelper, который будет принимать словарь и строку URI и преобразовывать их в URL с параметрами строки запроса. QueryHelpers.AddQueryString (строка uri, IDictionary queryString) Это часть Microsoft.AspNetCore.WebUtilities. Используя этот метод, я смог правильно подготовить свои данные формы. Для почтового запроса тест должен выглядеть следующим образом

//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
Client.DefaultRequestHeaders.Add("my-name", "admin");
Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data

var rawData = new Dictionary<string, string>(){{ "Id", "0"}, {"Name", "Controller Test Name"}, {"PointOfContact", "Tom Jerry"}
            , {"Email", "Tom.Jerry@yolo.comy"}, {"CreationTime", $"{DateTime.Now}"}, {"LastModificationTime", ""}, {"IsActive", "true"}, {"AddressId", "0"}
            , {"VendorAddress.Id", "0"}, {"VendorAddress.Address1", "123 This Way"}, {"VendorAddress.City", "Arlington"}, {"VendorAddress.State", "44"}, {"VendorAddress.Zip", "76001"}
            , {"VendorAddress.Phone", "8175555555"}, {"VendorAddress.Fax", ""}, {"VendorAddress.IsActive", "true"}, {"VendorAddress.CreationTime", $"{DateTime.Now}"}, {"VendorAddress.LastModificationTime", ""}
        };
var jsonData = JsonConvert.DeserializeObject(rawData);

//Serialize ViewModel to send with Post as part of the HttpContent object 
var data = JsonConvert.SerializeObject(viewModelSave);

//actually get the url from helper method 
var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor));

var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");

//Act
var response = await PostResponseAsObjectAsync<AjaxResponse>(url, content);

//Assert
var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });

response.ShouldBeOfType<AjaxResponse>();
response.Result.ShouldNotBeNull();
count.ShouldBe(3);

Отправить запрос теста будет выглядеть так

//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
Client.DefaultRequestHeaders.Add("my-name", "admin");
Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data

var rawData = new Dictionary<string, string>(){{ "Id", "0"}, {"Name", "Controller Test Name"}, {"PointOfContact", "Tom Jerry"}
            , {"Email", "Tom.Jerry@yolo.comy"}, {"CreationTime", $"{DateTime.Now}"}, {"LastModificationTime", ""}, {"IsActive", "true"}, {"AddressId", "0"}
            , {"VendorAddress.Id", "0"}, {"VendorAddress.Address1", "123 This Way"}, {"VendorAddress.City", "Arlington"}, {"VendorAddress.State", "44"}, {"VendorAddress.Zip", "76001"}
            , {"VendorAddress.Phone", "8175555555"}, {"VendorAddress.Fax", ""}, {"VendorAddress.IsActive", "true"}, {"VendorAddress.CreationTime", $"{DateTime.Now}"}, {"VendorAddress.LastModificationTime", ""}
        };
var jsonData = JsonConvert.DeserializeObject(rawData);

//Serialize ViewModel to send with Post as part of the HttpContent object 
var data = JsonConvert.SerializeObject(viewModelSave);

//actually get the url from helper method 
var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor));

var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
var message = new HttpRequestMessage {
    Content = content,
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localHost" + url)
};

//Act
var response = await SendResponseAsObjectAsync<AjaxResponse>(message);

//Assert
var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });

response.ShouldBeOfType<AjaxResponse>();
response.Result.ShouldNotBeNull();
count.ShouldBe(3);
...