Unit Testing Azure Functions With Dependency Injection - c#

I haven't written any Azure functions in quite a long time, and thought I'd refresh myself today, but I've clearly forgotten how to write appropriate unit tests for them. I have the following Function - it picks a random quote from a list;
public class QuoteFunction
{
private readonly IQuoteBank _repository;
public QuoteFunction(IQuoteBank repository)
{
_repository = repository;
}
[FunctionName("GetQuote")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
Quote quote = _repository.getQuote();
return new OkObjectResult(quote);
}
}
and it uses dependency injection to obtain the list of quotes - I have the following in Startup;
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IQuoteBank, QuoteBank>();
builder.Services.AddLogging();
}
which is injected into the constructor of the Function. as shown in the first snippet.
What I am struggling with is how I can use Moq to force the quote (which is randomly selected) to be consistent. I know I can mock the Interface IQuoteBank - but there is no where I can pass this mock object into the Run method.
So what I want to know is how I can pass a mock object to make the same quote be produced for unit testing? Has anyone done anything like this before? any examples in github?
I'm pretty sure I did a few years ago, just cant remember at all.

Setup the mock and pass that into the subject under test via constructor injection.
public async Task MyTestMehod() {
// Arrange
Mock<IQuoteBank> mock = new Mock<IQuoteBank>();
mock.Setup(_ => _.getQuote()).Returns("my consistent quote here")
var subject = new QuoteFunction(mock.Object);
//Act
IActionResult result = await subject.Run(Mock.Of<HttpRequest>(), Mock.Of<ILogger>());
//Assert
// ... assert my expected behavior
}

Related

How to write unit tests for Azure Functions that use wrapper?

I use a wrapper class on all of my Azure Functions:
public interface IFunctionWrapper
{
Task<IActionResult> Execute(HttpRequest req, ExecutionContext context, Func<Task<IActionResult>> azureFunction);
}
public class FunctionWrapper : IFunctionWrapper
{
private readonly ILogger _log;
public FunctionWrapper(ILogger<FunctionWrapper> log)
{
_log = log;
}
public async Task<IActionResult> Execute(HttpRequest req, ExecutionContext context, Func<Task<IActionResult>> azureFunction)
{
try
{
// Log few extra information to Application Insights
// Do authentication
return await azureFunction();
}
catch (Exception ex)
{
// Return a custom error response
}
}
}
And here is how it is used in a function:
public class MyFunctions
{
private readonly IFunctionWrapper _functionWrapper;
public MyFunctions(IFunctionWrapper functionWrapper)
{
_functionWrapper = functionWrapper;
}
public async Task<IActionResult> GetPost(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
ExecutionContext context,
ILogger log)
{
return await _functionWrapper.Execute(req, context, async () =>
{
// Function code...
return new JsonResult(post);
});
}
}
I am trying to write unit tests for this GetPost function. How can I mock the FunctionWrapper class in this situation?
Mock the desired behavior of the wrapper abstraction.
The following example uses MOQ to mock the wrapper. Pay attention to the setup of the mock
[TestClass]
public class MyFunctionsTests {
[TestMethod]
public async Task GetPost_Should_Execute_Wrapper() {
//Arrange
//mock the wrapper
IFunctionWrapper wrapper = Mock.Of<IFunctionWrapper>();
//configure the mocked wrapper to behave as expected when invoked
Mock.Get(wrapper)
.Setup(_ => _.Execute(It.IsAny<HttpRequest>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<Task<IActionResult>>>()))
.Returns((HttpRequest r, ExecutionContext c, Func<Task<IActionResult>> azureFunction) =>
azureFunction()); //<-- invokes the delegate and returns its result
MyFunctions function = new MyFunctions(wrapper);
//these should be initialized as needed for the test
HttpRequest req = null;
ExecutionContext ctx = null;
ILogger log = Mock.Of<ILogger>();
//Act
IActionResult result = await function.GetPost(req, ctx, log);
//Assert
result.Should().NotBeNull();
//verify that mocked wrapper was called
Mock.Get(wrapper).Verify(_ => _.Execute(It.IsAny<HttpRequest>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<Task<IActionResult>>>()));
//...perform other assertions here
}
}
The code in the original question omitted most of the body of the subject under test. That being said, this example is based on what was originally provided, which was used to create a reproducible example used to create the test above
You don't need to create a wrapper interface at all:
HttpRequest is mockable: https://mahmutcanga.com/2019/12/13/unit-testing-httprequest-in-c/
ExecutionContext can be mocked (or as its just a POCO used as-is)
ILogger can be mocked
Use dependency injection to inject the dependencies of the function (and mock those then).
Remember you really only want to test that parameter validation and possible parsing works correctly.

Unit Testing nested methods

While I understand that when unit testing a method it is very important to mock all it's dependencies, what I still have confusion about is what happens when the method is nested? Do I mock only the dependencies of the parent method or do I mock the dependencies of the child method(s) as well or do I set expectations on the calls to the dependent object and set the exact return values so that I can perform the test that I want?
For instance, in the below example, if we want to unit test the method B, do we only mock IHttpClientFactory & ILogger or do we also set the method's return value to what we are actually expecting because otherwise when the test method executes it goes ahead and tries to execute methodC where it fails because the value of client after the line var client = _clientFactory.CreateClient() executes is null?
using System.Net.Http;
...
public class classA
{
private readonly IHttpClientFactory _clientFactory;
private sting url = "...";
private ILogger _log { get; set; }
...
public classA(ILogger log, IHttpClientFactory clientFactory, ...)
{
_log = log;
_clientFactory = clientFactory;
...
}
public string methodB(string inputB)
{
var varB = methodC(inputB);
...
return ..;
}
public string methodC(string inputC)
{
...
var client = _clientFactory.CreateClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage httpResponseMessage = await client.PostAsync(url, new StringContent(inputC, Encoding.UTF8, "application/json"));
responJsonText = await httpResponseMessage.Content.ReadAsStringAsync();
...
return ..;
}
}
So you have an HTTP client, a high-level method that gets you some structured data and a low-level method that gets you the contents of the response.
These things are more of an art than hard-cut rules, but the rule I prefer most of the time is to write code that can have all of its I/O abstracted and then mock or test-implement the I/O itself. This way the most amount of business logic would be testable.
I/O can be many things - file, network, user input, but even things such as getting a certificate from the cert store or reading registry setting. Any data that originates at runtime from outside the process is I/O, no matter the method.
When you mock functionality, the most common things you're interested in is validating the method's input or emulating its output (or both). So in your mock, you shouldn't be too concerned with the actual implementation since you're not testing your mocked method - you're testing whatever is calling it.
So... about your sample code. If you're trying to test MethodB, you'd need MethodC to have a test implementation - either by mocking the HttpClient it relies on or by making it virtual and having it overridden in test.
Side note: reuse the HttpClient, keep it with the class

Integration tests with asp.net core (test of controllers without the views)

I am trying to setup a test project to test my controllers with identity and the database without having to define the views.
I have a unit test project where I can test my controller by instanciating it, passing the dbContext to the constructor.
public class EventControllerTests
{
private readonly IEventRepository _eventRepository;
private readonly EventController _controller;
private readonly AppDbContext dbContext;
const string cn = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=EventDb;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
public EventControllerTests()
{
var options = new DbContextOptionsBuilder<EVNTS.Web.Database.AppDbContext>()
.UseSqlServer(cn).Options;
dbContext = new EVNTS.Web.Database.AppDbContext(options);
// Arrange
_eventRepository = new EventRepository(dbContext);
_controller = new EVNTS.Web.Controllers.EventController(_eventRepository);
}
[Fact]
public void ActionIndexTest()
{
// Act
var result = _controller.Index(1);
// Assert
var model = (Event)result.Model;
Assert.Equal(1, model.Id);
}
}
I have an integration test project where I use a WebApplicationFactory
public class BasicTests : IClassFixture<WebApplicationFactory<EVNTS.Startup>>
{
private readonly WebApplicationFactory<EVNTS.Startup> _factory;
private readonly HttpClient _client;
public BasicTests(WebApplicationFactory<EVNTS.Startup> factory)
{
_factory = factory;
_client = _factory.CreateClient();
}
[Theory]
[InlineData("/")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Act
var response = await _client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
[Fact]
public async Task TestUserRegistration()
{
var s = _factory.Services.GetRequiredService<EVNTS.Web.Repositories.IEventRepository>();
var url = "/user/register";
var inputModel = new EVNTS.Web.ViewModels.RegisterModel()
{
UserName = "eric",
Password = "123456",
ConfirmPassword = "123456"
};
var sObj = JsonSerializer.Serialize(inputModel);
var content = new StringContent(sObj, Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _client.PostAsync(url, content);
var result = response.Content.ReadAsStringAsync();
}
}
The problem is that with the second option, the views have to be created and I need to use a library like AngleSharp to test the results.
I would like something in between where I can call the contructor directly and test the result view but with the DI injecting the UserManager and the dbContext for me.
any ideas?
Cheers
Here is the controller:
public class UserController : Controller
{
private readonly UserManager<User> _userManager;
public UserController(UserManager<User> userManager)
{
_userManager = userManager;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterModel model)
{
IdentityResult? result=null;
if (ModelState.IsValid)
{
var user = await _userManager.FindByNameAsync(model.UserName);
if (user == null)
{
user = new User
{
Id = Guid.NewGuid(),
UserName = model.UserName,
};
result = await _userManager.CreateAsync(user, model.Password);
}
}
return View(result);
}
}
I also find this usefull sometimes when you want to check the result of a controller in an integration test condition without checking the view.
You can use the dependency injection and create a scope from the WebApplicationFactory.
using (var serviceScope = Factory.Services.CreateScope())
{
var sut= serviceScope.ServiceProvider.GetService<YourController>();
}
To make this work you have to call the method AddControllersAsServices() in Startup.cs to register the controller in the DI container
services.AddControllersWithViews(options => { options.ConfigureMvcOptionsForPortalModule(); })
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddControllersAsServices();//add controller in DI to access it in integration testing
There is no in between. The first example is a unit test, while the second is an integration test. If you want to just look at the result object of the action, then you'd use the unit test methodology, and you'd need to mock out your dependencies. Otherwise, you'd use the integration test approach, and you have to deal with the actual simulated server response.
For what it's worth here, controller actions should be integration tested, since they are inherently dependent on a number of components coming together, so you should be following the second approach, parsing the HTML response, if necessary.
I don't consider myself an authority on how to perform unit testing, but since the comment section is restricted in characters I will write my comments here.
Usually, when you find yourself in a situation where it's difficult to come up with a good unit test (I won't define "good" here) more often than not, it is because there are some problems with the project structure/code design, and not actual limitations of the unit testing itself (again, not that unit testing doesn't have it's limitations, but I think this is not the case here).
Based on the above I asked you to include the action's code so we can examine what exactly are you trying to test and why it is so hard.
Here comes the heavily opinion-based part of my comment, but I leave it up to you wether you would want to take some of this or leave it.
It's not a rule, but a good rule of thumb is that the controller should contain very little business logic, which means that unit testing a controller should be basically testing the different paths that the request could go, once it hits the controller.
Generally you would want something like this:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await _userManager.FindByNameAsync(model.UserName);
...
return View(result);
which then you can unit test with something like this:
public async Task Register_Returns_BadRequest_On_Invalid_Model()
{
var testUsername = "TestUsername";
var mockUserManager = new Mock<IUserManager>();
mockUserManager.Setup(m => m.FindByNameAsync(testUsername))
.Returns(Task.FromResult(**Not sure about this part**))
var controller = new RegisterController(mockUserManager.Object);
var result = await controller.Register(model: null);
var actionResult = Assert.IsType<ActionResult<IdentityResult>>(result);
Assert.IsType<BadRequestObjectResult>(actionResult.Result);
}
For the happy path you want only to check that on a valid ModelState the result is of type ActionResult>
What is my idea:
When you unit test the controller you should not be bothered by the actual data, this is responsibility of other parts of the application
The controller unit test should be plain simple, most of the time you should be testing only those two cases - invalid data returns some sort of BadRequest, valid data returns the expected response
If you find yourself mocking too much objects most of the time it's a clear sign that you need some additional layer of abstraction.
In your case, in order to make my code better structured and easier for testing I would do the following:
First test for invalid ModelState - you don't want to proceed if the ModelState is invalid and this should also be covered by an unit test.
Managers should be a higher level of abstraction. Methods like FindByNameAsync and CreateAsync are more suitable for the data access layer. In the case of this action, your UserManager can have a method like Register so your controller's action look like this:
if (!ModelState.IsValid)
{
return BadRequest()
}
var result = _userManager.Register(model.UserName);
return View(result);
Now you can remove the Find and Create methods from the controller and create a UserRepository where I thin those methods belong and where you can test them in isolation.
In this setup You have these abstractions Controller -> Manager -> Repository. Now you try to test the three of these in one single method, which is causing the problems in my opinion.
Also, just because I find this a bit more tidy, usually you use a Service layer and if the structure is too complex you add the manager layer so it becomes Controller -> Manager -> Service -> Repository. In your case I'm not sure that you need this complexity so maybe just for the sake of better naming, rename the UserManager to UserService, so that your code flow is Controller -> Service -> Repository.
Also, last pease of advice. Controller testing has always been contraversial so don't be too bothered if you don't cover your controller with unit tests as much as other parts of the code. This is somewhat expected, what I wanted to tell with this post is mainly that the problem wasn't how to test but rather is the code testable as it is, which in my opinion could be improved as I've shown above. Yes, my proposition is not perfect as well but it creates smaller chunks of code which are encapsulated, don't have that many dependencies which ultimately makes them easier to test. And of course this is not a substitution of the integrations tests.
Hope this gave you some food for thought.

AzureFunctions.Autofac threadsafe dependency injection issue

I am using AzureFunctions.Autofac to inject into my Azure Functions web api. An example of the config:
public class DIConfig
{
public DIConfig()
{
DependencyInjection.Initialize(builder =>
{
// DAL
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerLifetimeScope();
builder.RegisterType<SecretCompanyContext>().InstancePerLifetimeScope();
builder.RegisterType<SecretCompanyContext>().As<ICartContext>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope();
// Services
builder.RegisterType<InventoryServices>().As<IInventoryServices>().InstancePerLifetimeScope();
// Controllers ported from ASP.NET MVC Web API
builder.RegisterType<InventoryController>().InstancePerLifetimeScope();
});
}
Then my Azure functions, I have one class that defines all methods in the API
[DependencyInjectionConfig(typeof(DIConfig))]
public class InventoryFunctions : FunctionsApi
{
[FunctionName("GetProductsByCategory")]
// /inventory/categories/{id}/products
public static async Task<HttpResponseMessage> GetProductsByCategory(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "inventory/categories/{id}/products")]
HttpRequestMessage req,
TraceWriter log,
int id,
[Inject] InventoryController controller)
{
// do stuff
var result = await controller.GetProductsByCategory(id);
return JsonResponse(result, HttpStatusCode.OK);
}
[FunctionName("GetInventoryBySku")]
// /inventory/skus?sku=ASDF&sku=ASDG&sku=ASDH
public static async Task<HttpResponseMessage> GetInventoryBySku(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "inventory")]
HttpRequestMessage req,
TraceWriter log,
[Inject] InventoryController controller)
{
// do stuff
var result = await controller.QueryInventoryBySkuList(skuList);
return JsonResponse(result, HttpStatusCode.OK);
}
[FunctionName("UpdateProductsQuantity")]
// /inventory
// Post
public static async Task<HttpResponseMessage> UpdateProductsQuantity(
[HttpTrigger(AuthorizationLevel.Function, "put", Route = "inventory")]
HttpRequestMessage req,
TraceWriter log,
[Inject] InventoryController controller)
{
// do stuff
var inventoryProducts = await req.Content.ReadAsAsync<List<InvProductOperation>>();
var result = await controller.UpdateAvailableProductsQuantity(inventoryProducts);
return JsonResponse(result, HttpStatusCode.OK);
}
But I keep getting this error:
A second operation started on this context before a previous
asynchronous operation completed. Use 'await' to ensure that
any asynchronous operations have completed before calling
another method on this context. Any instance members are not
guaranteed to be thread safe.
I have verified that async and await are used properly, so following the error message's recommendation isn't fixing it. What appears to be the issue is that IDbContext is not honoring the InstancePerLifetimeScope as expected. Is this happening because I have more than one method in my InventoryFunctions class? Or is AzureFunctions.Autofac not threadsafe?
Change the registration of the DbContext to this:
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();
You can find a deeper explanation of mine for why this is happening here.
I was going by this SO answer: Autofac - InstancePerHttpRequest vs InstancePerLifetimeScope which said that InstancePerLifetimeScope was the non-ASP.NET equivalent of InstancePerRequest.
I spoke to the developers and they said the truth is that getting one DbContext per HttpRequest was the default behavior when you simply register using builder.RegisterType<SecretCompanyContext>.As<IDbContext>() so there's some misinformation out there.
So the solution is, instead of using
builder.Register<IDbContext>(c => new SecretCompanyContext()).InstancePerDependency();
or
builder.RegisterType<SecretCompanyContext>().As<IDbContext>().InstancePerLifetimeScope();
one should just use
builder.RegisterType<SecretCompanyContext>().As<IDbContext>();
if the goal is one instance per HTTP request.

Unit Testing a controller that uses windows authentication

-------Please see updates below as I now have this set up for dependency injection and the use of the MOQ mocking framework. I'd still like to split up my repository so it doesn't directly depend on pulling the windowsUser within the same function.
I have a Web API in an intranet site that populates a dropdown. The query behind the dropdown takes the windows username as a parameter to return the list.
I realize I don't have all of this set up correctly because I'm not able to unit test it. I need to know how this "should" be set up to allow unit testing and then what the unit tests should look like.
Additional info: this is an ASP.NET MVC 5 application.
INTERFACE
public interface ITestRepository
{
HttpResponseMessage DropDownList();
}
REPOSITORY
public class ExampleRepository : IExampleRepository
{
//Accessing the data through Entity Framework
private MyDatabaseEntities db = new MyDatabaseEntities();
public HttpResponseMessage DropDownList()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
//Pass the parameter to a procedure running a select query
var sourceQuery = (from p in db.spDropDownList(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
public ExampleController()
{
_exampleRepository = new ExampleRepository();
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 1
I have updated my Controller based on BartoszKP's suggestion to show dependency injection.
UPDATED CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
//Dependency Injection
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 2
I have decided to use MOQ as a mocking framework for unit testing. I'm able to test something simple, like the following. This would test a simple method that doesn't take any parameters and doesn't include the windowsUser part.
[TestMethod]
public void ExampleOfAnotherTest()
{
//Arrange
var mockRepository = new Mock<IExampleRepository>();
mockRepository
.Setup(x => x.DropDownList())
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
ExampleController controller = new ExampleController(mockRepository.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var response = controller.DropDownList();
//Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
I need help testing the DropDownList method (one that does include code to get the windowsUser). I need advice on how to break this method apart. I know both parts shouldn't been in the same method. I don't know how to arrange splitting out the windowsUser variable. I realize this really should be brought in as a parameter, but I can't figure out how.
You usually do not unit-test repositories (integration tests verify if they really persist the data in the database correctly) - see for example this article on MSDN:
Typically, it is difficult to unit test the repositories themselves, so it is often better to write integration tests for them.
So, let's focus on testing only the controller.
Change the controller to take IExampleRepository in its constructor as a parameter:
private IExampleRepository _exampleRepository;
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
Then, in your unit tests, use one of mocking frameworks (such as RhinoMock for example) to create a stub for the sole purpose of testing the controller.
[TestFixture]
public class ExampleTestFixture
{
private IExampleRepository CreateRepositoryStub(fake data)
{
var exampleRepositoryStub = ...; // create the stub with a mocking framework
// make the stub return given fake data
return exampleRepositoryStub;
}
[Test]
public void GivenX_WhenDropDownListIsRequested_ReturnsY()
{
// Arrange
var exampleRepositoryStub = CreateRepositoryStub(X);
var exampleController = new ExampleController(exampleRepositoryStub);
// Act
var result = exampleController.DropDownList();
// Assert
Assert.That(result, Is.Equal(Y));
}
}
This is just a quick&dirty example - CreateRepositoryStub method should be of course extracted to some test utility class. Perhaps it should return a fluent interface to make the test's Arrange section more readable on what is given. Something more like:
// Arrange
var exampleController
= GivenAController()
.WithFakeData(X);
(with better names that reflect your business logic of course).
In case of ASP.NET MVC, the framework needs to know how to construct the controller. Fortunately, ASP.NET supports the Dependency Injection paradigm and a parameterless constructor is not required when using MVC unity.
Also, note the comment by Richard Szalay:
You shouldn't use HttpContext.Current in WebApi - you can use base.User which comes from HttpRequestBase.User and is mockable. If you really want to continue using HttpContext.Current, take a look at Mock HttpContext.Current in Test Init Method
One trick that I find very useful when trying to make old code testable when said code is accessing some global static or other messy stuff that I can't easily just parameterize is to wrap access to the resource in a virtual method call. Then you can subclass your system under test and use that in the unit test instead.
Example, using a hard dependency in the System.Random class
public class Untestable
{
public int CalculateSomethingRandom()
{
return new Random().Next() + new Random().Next();
}
}
Now we replace var rng = new Random();
public class Untestable
{
public int CalculateSomethingRandom()
{
return GetRandomNumber() + GetRandomNumber();
}
protected virtual int GetRandomNumber()
{
return new Random().Next();
}
}
Now we can create a testable version of the class:
public class Testable : Untestable
{
protected override int GetRandomNumber()
{
// You can return whatever you want for your test here,
// it depends on what type of behaviour you are faking.
// You can easily inject values here via a constructor or
// some public field in the subclass. You can also add
// counters for times method was called, save the args etc.
return 4;
}
}
The drawback with this method is that you can't use (most) isolation frameworks to implement protected methods (easily), and for good reason, since protected methods are sort of internal and shouldn't be all that important to your unit tests. It's still a really handy way of getting things covered with tests so you can refactor them, instead of having to spend 10 hours without tests, trying to do major architectual changes to your code before you get to "safety".
Just another tool to keep in mind, I find it comes in handy from time to time!
EDIT: More concretely, in your case you might want to create a protected virtual string GetLoggedInUserName(). This will technically speaking keep the actual call to HttpContext.Current.User.Identity.Name untested, but you will have isolated it to the simplest smallest possible method, so you can test that the code is calling the correct method the right amount of times with the correct args, and then you simply have to know that HttpContext.Current.User.Identity.Name contains what you want. This can later be refactored into some sort of user manager or logged in user provider, you'll see what suits best as you go along.

Categories