Iris Shing Ответов: 1

Как получить значение сеанса с помощью макета?


Я пишу API, используя c#.Net сердечник

Один из моих API используется для генерации капчи, а затем хранения в сеансе, я использую Redis для хранения сеанса здесь.

А теперь я пытаюсь написать модульный тест для API.
Потому что API входа в систему должен был передать captcha, поэтому мне нужно получить значение captcha из сеанса.
Я использую Moq для написания модульного теста.
Мой код находится ниже:

Капчи по API:
ILogger<CommonApiController> _logger;
private readonly ISessionWapper _sessionWapper;
string _captcha;

public CommonApiController(ISessionWapper sessionWapper, BaseContext db, IOptions<JwtSetting> options, ILogger<CommonApiController> logger,
            IOptions<SettingModel> sysSetting)
            : base(db, options, logger, sysSetting)
        {
            _logger = logger;
            _sessionWapper = sessionWapper;
        }
public CommonApiController(ISessionWapper sessionWapper, ILogger<CommonApiController> logger)
          : base()
        {
            _logger = logger;
            _sessionWapper = sessionWapper;
        }

[HttpGet("Captcha")]
[ProducesResponseType(typeof(FileResult), 200)]
public async Task<FileResult> GetCaptcha()
{
            try
            {
                var captcha = Captcha.GenerateRandomText(4);
             
                await _sessionWapper.Set(captcha);
                var session = await _sessionWapper.Get();
                _captcha = session;
                _logger.LogDebug(session);
                return File(Captcha.GenerateCaptchaImage(captcha), "image/gif");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.StackTrace);
                return File("ERROR", "image/gif");
            }
        }


Помощник по сеансу:
public static class SessionExtensions
{
    public static void SetObject<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T GetObject<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
    }
}
public interface ISessionWapper
{
    CaptchaSessionModel Captcha { get; set; }
    Task<string> Get();
    Task Set(string value);
}
public class SessionWapper : ISessionWapper
{
    private static readonly string _captchaKey = "captchaKey";
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SessionWapper(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    public void Clear()
    {
        Session.Clear();
    }
    private ISession Session
    {
        get => _httpContextAccessor.HttpContext.Session;
    }
    public async Task<string> Get()
    {
        await _httpContextAccessor.HttpContext.Session.LoadAsync();
        return Captcha.value;
    }
    public async Task Set(string value)
    {
        Captcha = new CaptchaSessionModel { value = value };
        await _httpContextAccessor.HttpContext.Session.CommitAsync();
    }
    public CaptchaSessionModel Captcha
    {
        get => Session.GetObject<CaptchaSessionModel>(_captchaKey);
        set => Session.SetObject(_captchaKey, value);
    }

}
public struct CaptchaSessionModel
{
    public string value { get; set; }
}


API Входа В Систему:
private readonly ISessionWapper _sessionWapper;

ILogger<LoginController> _logger;

public LoginController(ISessionWapper sessionWapper, BaseContext db, IOptions<JwtSetting> options, ILogger<LoginController> logger, IOptions<SettingModel> settingModel)
            : base(db, options, logger, settingModel)
        {
            _logger = logger;
            _sessionWapper = sessionWapper;
        }

[HttpPost("Login/Login")]
        [ProducesResponseType(typeof(DisplayResponseLogin), 200)]
        public async Task<IActionResult> Login([FromBody]LoginRequestModel model)
        {
            try
            {
                var session = await _sessionWapper.Get();
                _logger.LogDebug(JsonConvert.SerializeObject(_sessionWapper.Captcha));

                _logger.LogDebug(session);
                if (string.IsNullOrEmpty(session) || !model.captcha.Equals(session))
                {
                    return Result(new BaseDalResponseModel { status = MobileHis.Enums.ResponseStatus.CaptchaIncorrect_3 });
                }
                
//some login code ....

                var now = DateTime.UtcNow;

                JwtHelper jwtHelper = new JwtHelper(dal, _options);
                var encodedJwt = jwtHelper.GenerateToken(acc, model.remember);//, apis);

                var response = new LoginResponseModel
                {
                    access_token = encodedJwt,
                    expires_in = (int)_options.Expire,
                   
                };
               

                return Result(new BaseDalResponseModel { status = MobileHis.Enums.ResponseStatus.OK_0, content = response });

            }
            catch (Exception ex)
            {
                Logging(_logger, LoggingEvents.Login, ex.Message, MobileHis.Enums.ResponseStatus.Error_99);
                return BadRequest();
            }

        }


Автозагрузки.в CS
public void ConfigureServices(IServiceCollection services)
        {
          
            services.AddMvc();

            //services.AddDistributedMemoryCache(); 
            services.AddDistributedRedisCache(options =>
            {
                options.Configuration = "localhost:6379";
            });
            services.AddSession(options =>
            {
              
                options.Cookie.Name = "cookieName";
                options.IdleTimeout = TimeSpan.FromMinutes(5);
            });

          
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<ISessionWapper, SessionWapper>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
           
            // This session call MUST go before UseMvc()
            app.UseSession();

            //base
            app.UseMvc();
        }


Что я уже пробовал:

Вот мой тестовый код
[Fact]
       public async Task TestGetCaptcha()
       {
           ILoggerFactory f = new LoggerFactory();
           ILogger<CommonApiController> logger = f.CreateLogger<CommonApiController>();

           // Arrange
           var mockRepo = new Mock<ISessionWapper>();
           var controller = new CommonApiController(mockRepo.Object, logger);

           // Act
           var result = await controller.GetCaptcha();
           var captcha = //how to get captcha value here?
           // Assert
           var redirectToActionResult =
               Assert.IsType<RedirectToActionResult>(result);
           Assert.Equal("Home", redirectToActionResult.ControllerName);
           Assert.Equal("Index", redirectToActionResult.ActionName);
       }


или я должен издеваться над сервером?
public class TestClientProvider : IDisposable
   {
       private TestServer _server;
       public HttpClient Client { get; private set; }

       public TestClientProvider(string baseAddress= "http://myapp.localhost:5000")
       {
          var server = new Mock<TestServer>(new WebHostBuilder().UseStartup<Startup>());
           _server = server.Object;
           //_server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
           Client = _server.CreateClient();
           Client.BaseAddress = new Uri(baseAddress);
           Client.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest"); ;
       }

       public void Dispose()
       {
           _server?.Dispose();
           Client?.Dispose();
       }
   }



Спасибо!

F-ES Sitecore

модульные тесты не должны иметь доступа к каким-либо внешним ресурсам, они не должны вызывать URL-адреса, они не должны зависеть от HttpApplication и т. д. Что вам нужно сделать, так это использовать moq для настройки методов на вашем издевательском ISessionWrapper, чтобы они возвращали жестко закодированные значения, если методы Get\Set вызываются с ожидаемыми параметрами.

Iris Shing

понял! Большое спасибо.

1 Ответов

Рейтинг:
2

mehr.ah

В интеграционном тесте вам не нужно получать реальное значение captcha, но в UI /Real test вам нужно взять его, но не из mock framework.


Iris Shing

Спасибо за ваш ответ.
Но большинство API-интерфейсов должны были войти в систему, чтобы получить токен, в противном случае они возвращают 400, 403.
Вот почему я хочу получить реальную ценность сеанса.

Итак, если я хочу получить сеанс, я не должен использовать mock?