Search code examples
c#asp.net-coreintegration-testing

How to pass TempData value in integration test to get in .net core pages


I am using TempData for passing a value (Email) from SetPassword page to SetPasswordConfirmation page in asp.net core. It is working as expected. But I am not able to get this TempData value in an integration test method.

    private readonly HttpClient _client;

    public SetPasswordTest(CustomWebApplicationFactory factory)
    {
        _client = factory.CreateClient();
    }

    //Test method
    [Fact]
    public async Task POST_WithValidEmail_ShouldRedirectToHomePage()
    {   
        var httpContext = new DefaultHttpContext();
        var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
        tempData["Email"] = TestData.TestUserEmail;
        var redirectLink = "~/Account/Manage";
        var setPasswordConfirmationLink = GetSetPasswordConfirmationLink();

        var response = await _client.SubmitAsync(setPasswordConfirmationLink, new
        {
            ReturnUrl = redirectLink,
            TempData = tempData
        }); 

        response.AssertOnPage(redirectLink);
        response.EnsureSuccessStatusCode();
    }

    //Page post method
    public async Task<IActionResult> OnPostAsync(string returnUrl) 
    {   
        ApplicationUser user = null;
        if(!string.IsNullOrEmpty(**Email**)) user = await _userManager.FindByEmailAsync(Email);
        //...
    }

I am not getting Email value in OnPostAsync method during the integration test.


Solution

  • There's a number of things wrong here. First, you cannot modify TempData in an integration test like this. In general, when you a testing some sort of persisted state, you need to implement the entire flow in your test. For example, I'm assuming in an actual usage scenario, the user would have accessed a previous page where they would have submitted their email address in the first place. Your test should request this action, passing the email in the post body, just as the user would have, first, and then request this action that you're actually testing.

    Second, TempData won't work for this anyways. For a password reset workflow, a user gets emailed a link, which they will click to return to your site. TempData will not survive that even if all the stars align correctly and the user immediately clicks the link on the same device, opening it in the same browser. Add to that that the user could open the link on an entirely different device, long after it was delivered, potentially after doing other stuff on your site, and it becomes even more broken.

    To implement this correctly, the email address must either be included in the link itself or the user must re-enter it on the password reset form. You cannot use something like TempData or Session in a way that will work in all scenarios.