Как получить значение сеанса с помощью макета?
Я пишу 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
понял! Большое спасибо.