1

I'm trying to mock HttpContext to test my UsersController. The UsersController inherit from

public abstract class ControllerBase

and HttpContext is a property of ControllerBase

public HttpContext HttpContext { get; }

and here is the method in the UsersContoller, which I want to test

 public async Task<IActionResult> Register([FromBody] UserViewModel model)
        {
            _logger.LogDebug("Register new user");

            var user = mapper.Map<User>(model);
            user.Company.Active = false;

            var result = await userManager.CreateAsync(user, model.Password);

            if (result.Succeeded)
            {
                await userManager.AddToRoleAsync(user, Roles.NO_ACCESS);

                //send confirmation email

                string confirmationToken = userManager.GenerateEmailConfirmationTokenAsync(user).Result;

                HostString hostString = HttpContext.Request.Host; //I need to mock httpcontext for this 

                this.mailSender.SendConfirmationMailAsync(user, hostString, confirmationToken);

                return Ok();
            }
            else
            {
                _logger.LogInformation("User could not be registered Errors:");
                result.Errors.ToList().ForEach(e => _logger.LogInformation(e.Description));

                return BadRequest(result.Errors);
            }

        }

this is my BaseTestContoller, in which setup for tests is initialized

[SetUp]
        public void Setup()
        {
            var dbContext = CreateDbContext();

            CreateUserManager();
            CreateMailSender(dbContext);
            CreateMockImapper();
            CreateMockIlogger();
            
            usersController = new Mock<UsersController>(
               userManagerMock.Object,
               new CompanyService(dbContext),
               mailSenderMock,
               new Mock<IConfiguration>().Object,
               iMapperMock.Object,
               iLoggerFactoryMock.Object);

        }

i've tried many options, but it wasn't successful therefor it would be nice if someone could help me. Thanks in advance

UPDATE

usersController = new Mock<UsersController>(
               userManagerMock.Object,
               new CompanyService(dbContext),
               mailSenderMock,
               new Mock<IConfiguration>().Object,
               iMapperMock.Object,
               iLoggerFactoryMock.Object);

            var conterllerContext = new ControllerContext() { HttpContext = new DefaultHttpContext() { } };                             
            HostString host = new HostString("test.de");

            conterllerContext.HttpContext.Request.Host = host;

            usersController.Setup(c => c.HttpContext).Returns(conterllerContext.HttpContext);

Now i have a problem with setting up. userController.setup returns this msg : System.NotSupportedException : Unsupported expression: c => c.HttpContext Non-overridable members (here: ControllerBase.get_HttpContext) may not be used in setup / verification expressions.

ppouria
  • 13
  • 7
  • This is an example, which I've tried out and doesn't work `HttpContext context = new DefaultHttpContext(); HostString host = new HostString("test.de"); context.Request.Host = host;` `usersController.Setup(c => c.HttpContext).Returns(context);` – ppouria Apr 14 '21 at 14:39
  • 2
    Personally I would not mock the HttpContext but create an interface with a method that gives you the host and make two implementations: a mock implementation and the one that uses HttpContext to give the real host. You can use the mock in your tests and use the real one in production. – lordvlad30 Apr 14 '21 at 15:33
  • @lordvlad30 The problem is that "Controllbase" is part of "Microsoft.AspNetCore.Mvc".and I can't change it. Therefor I need to mock it. But next time i will do it in your way. Thanks – ppouria Apr 15 '21 at 06:30

2 Answers2

0

You can use ControllerContext to set the context to be DefaultHttpContext which you can modify to your needs.

var ctx = new ControllerContext() { HttpContext = new DefaultHttpContext()};
var tested = new MyCtrl();
tested.ControllerContext = ctx;
shubhkr1
  • 94
  • 2
  • 15
  • First of all, thanks for your answer. Do you know how I could set my mocked userController up to return this Httpcontxt ? – ppouria Apr 15 '21 at 06:52
0

Can't you make a mock service for getting the host address (I am not really familiar with mock libraries).

Something like this:

class IHostService {
 string GetHost();
}

public class HostService {
  // create constructor with httpcontextaccessor    
 public string GetHost() {
  return _httpContextAccessor.HttpContext.Request.Host;
 }
}
public class MockHostService {
  public string GetHost() {
    return "test.de";
  }
}

and in your mock class you can probably add this service just like you added mailSenderMock. And in your controller you use string host = _hostService.GetHost().

lordvlad30
  • 391
  • 1
  • 17
  • Thanks for your suggestion this is the solution. https://stackoverflow.com/questions/61269967/error-trying-to-create-mock-ofcontrollercontext-for-asp-net-core-3-1-unit-te – ppouria Apr 15 '21 at 07:33