如何使用mock获取会话值? [英] How to get session value using mock?
问题描述
我正在使用c#.Net Core编写API
我的一个API用于生成验证码然后存储到会话中,我正在使用Redis来在这里存储会话。
现在我正在尝试为API编写单元测试。
导致需要通过登录API验证码,所以我需要从会话中获取验证码值。
我正在使用Moq编写单元测试。
我的代码如下:
Captcha api:
I'm writing APIs using c#.Net Core
One of my APIs is used to generate captcha then store to the session, I'm using Redis to store session here.
And now I'm trying to write a unit test for the APIs.
Cause the login API needed to pass captcha, so I need to get the captcha value from the session.
I'm using Moq to write the unit test.
My code is below:
Captcha 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");
}
}
会话助手:
Session helper:
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:
Login 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();
}
}
Startup.cs
Startup.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();
}
我的尝试:
这是我的单元测试代码
What I have tried:
Here is my unit test code
[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);
}
或我应该嘲笑服务器?
or I should mock the server?
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();
}
}
谢谢!
Thank you!
推荐答案
在集成测试中,您不需要获得验证码的真正价值,但在UI / Real测试中,您需要接受它,但不能从模拟框架中获取。
In integration test you do not need to get a real value of captcha but in UI /Real test you need to take it but not from mock framework.
这篇关于如何使用mock获取会话值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!