Flurl и HttpTest: модульные тесты не работают при выполнении всех, но проходят при индивидуальном запуске

Обновление: HttpTest не является потокобезопасным, согласно ошибке GitHub< /а>. Пока проблема не будет решена, тесты с использованием HttpTest нельзя запускать параллельно.

У меня есть действительно странная пара тестов с использованием Flurl и xUnit, которые при запуске всех в VS Test Explorer завершатся неудачей, но если они будут запущены по отдельности, они будут пройдены. Я не могу на всю жизнь увидеть, где эти 2 даже связаны друг с другом, но они есть.

Я извлек их из своего проекта в новый проект, и проблема не устранена. Я объединил их в 7z для всех, кто хочет загрузить его в VS, но полный код следует ниже.

Project.Commons

ПолучитьApi1:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;

namespace Project.Commons
{
    public class GetApi1
    {

        public async Task<string> ExecuteAsync(string token)
        {
            string apikeyKeyname = "token";

            dynamic response = await "http://www.api.com"
                .SetQueryParams(new { token = token })
                .GetJsonAsync();

            string receivedApiKey = ((IDictionary<string, object>)response)[apikeyKeyname].ToString();

            return receivedApiKey;
        }
    }
}

ПолучитьApi2:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;

namespace Project.Commons
{
    public class GetApi2
    {
        public async Task<IList<string>> ExecuteAsync()
        {
            var responses = await "http://www.api.com"
                .GetJsonAsync<List<string>>();

            var result = new List<string>();

            foreach (var response in responses)
            {
                result.Add("refined stuff");
            }

            return result;
        }
    }
}

Проект.Тесты

UnitTest1:

using Project.Commons;

namespace Project.Tests
{
    public class UnitTest1
    {
        private ITestOutputHelper output;
        public UnitTest1(ITestOutputHelper output)
        {
            this.output = output;
        }

        [Fact]
        public async Task ShouldBeAbleToGetApiKeyFromToken()
        {
            // Arrange
            using (var httpTest = new HttpTest())
            {
                var jsonResponse = new { token = "abcdef" };
                string expectedApiKey = "abcdef";
                httpTest.RespondWithJson(jsonResponse);
                var api = new GetApi1();

                // Act
                var receivedApiKey = await api.ExecuteAsync("mockToken");
                output.WriteLine("Received apikey = " + receivedApiKey);

                // Assert
                Assert.Equal(expectedApiKey, receivedApiKey);
            }
        }
    }
}

UnitTest2

using Flurl.Http.Testing;
using Project.Commons;
using Xunit;
using Xunit.Abstractions;

namespace Project.Tests
{
    public class UnitTest2
    {


        #region Mock API JSON Response
        private IList<string> mockResponse = new List<string>()
        {
            "raw stuff", "raw stuff", "raw stuff"
        };
        #endregion

        #region Expected Result
        private IList<string> expectedResult = new List<string>()
        {
            "refined stuff", "refined stuff", "refined stuff"
        };
        #endregion

        [Fact]
        public async Task CanGetProjectsByWeek()
        {
            // Arrange
            using (var httpTest = new HttpTest())
            {
                httpTest.RespondWithJson(mockResponse);

                // Act
                var api = new GetApi2();
                var actualResult = await api.ExecuteAsync();

                // Assert
                Assert.Equal(expectedResult,actualResult);
            }
        }
    }
}

person batrand    schedule 30.06.2016    source источник
comment
Не очень много работал с xunit - тесты выполняются параллельно? Потому что глядя на класс HttpTest , это не совсем похоже на то, что он хорошо работает с несколькими потоками.   -  person Damien_The_Unbeliever    schedule 30.06.2016
comment
да, тесты идут параллельно. Итак... есть ли альтернатива HttpTest или способ сделать его асинхронным?   -  person batrand    schedule 30.06.2016
comment
Я попытался удалить все ключевые слова async из тестов и вместо await api.ExecuteAsync() попробовал ExecuteAsync().Result. Тесты из одного и того же класса тестов будут пройдены, но тесты из других классов не пройдены. Похоже, что классы по-прежнему выполняются асинхронно.   -  person batrand    schedule 30.06.2016
comment
При беглом взгляде на xunit кажется, что он по умолчанию запускает модульные тесты в разных классах параллельно. И здесь нас убивает параллелизм, а не async.   -  person Damien_The_Unbeliever    schedule 30.06.2016
comment
Я не вижу способа быстро это исправить. Похоже, что Flurl использует глобальную систему конфигурации. HttpTest работает, переписывая эту конфигурацию. А затем сбросить все обратно к значениям по умолчанию, когда оно будет удалено, что не сработает, если их несколько.   -  person Damien_The_Unbeliever    schedule 30.06.2016
comment
Таким образом, кажется, что нет решения этой проблемы, кроме как не использовать HttpTest. Хм...   -  person batrand    schedule 30.06.2016


Ответы (1)


Комментарии верны - отсутствие безопасности потоков является известным ограничением HttpTest. Оно зарегистрировано и расследуется. Параллельное тестирование сегодня гораздо более распространено, чем всего пару лет назад, когда оно было создано, поэтому, хотя исправление не является тривиальным, мы относимся к нему с высоким приоритетом.

person Todd Menier    schedule 03.08.2016