Unit testing mvc model with HttpContext.Current.User.Identity.GetUserId() - unit-testing

In my MVC5 application, I have a Log entity, that is used to log any call to any controler. This log uses: HttpContext.Current.User.Identity.GetUserId() to determine the identity of the user accessing the controller.
public class Log
{
public Log()
{
TS = DateTime.Now;
UserId = HttpContext.Current.User.Identity.GetUserId();
}
[Required]
public Int32 Id { get; set; }
public string UserId { get; set; }
[Display(Name = "TS", ResourceType = typeof(Resources.Models.Log.Log))]
[Required(ErrorMessageResourceType = typeof(Resources.Models.Log.Log), ErrorMessageResourceName = "RequiredTS")]
public DateTime TS { get; set; }
[Required]
public short LogTypeId { get; set; }
[Display(Name = "LogText", ResourceType = typeof(Resources.Models.Log.Log))]
public string LogText { get; set; }
public ApplicationUser User { get; set; }
}
When I try to unit test a controller and crating an instance of the log class I get this error:
threw exception: System.NullReferenceException: Object reference not
set to an instance of an object.
at DASU.Core.Models.Log..ctor()
I know this is because the context is not set.
So my question is how do I set the context, or how do I mock the context, so I can create the Log for my test?

You should avoid coupling to HttpContext. Like suggested in the comments you could simplify your log my injecting the UserId into the dependent Log class
public class Log
{
public Log(string userId)
{
TS = DateTime.Now;
UserId = userId;
}
//...other code removed for brevity
}
or abstracting away the calls to HttpContext so that you can mock your abstract and inject that instead of trying and mock HttpContext
public interface IUserProvider {
string GetUserId();
}
You production implementations can wrap calls to HttpContext and you can easily create mock implementations for your unit tests.
public class Log
{
public Log(IUserProvider userProvider)
{
TS = DateTime.Now;
UserId = userProvider.GetUserId();
}
//...other code removed for brevity
}

Related

How to inject a service into a constructor when creating a new instance of an object?

The Setup: I've registered a configuration service that pulls data from appsettings.json and it works fine. I also have a controller that uses that service to get settings from that file, again this works like it's supposed to:
public class ApiController : Controller
{
private readonly string _apiUri;
public ApiController(IOptions<Configurator> config)
{
_apiUri = config.Value.ApiSettings.ApiBaseUrl +
config.Value.ApiSettings.ApiVersion;
}
//...
}
Now note, I'm new to automated unit testing and to asp.net core. What I'd like to do is to decouple the ApiController's reliance on the injected service so that I can use a separate XUnit test project to test functions inside the controller, similar to the example in this tutorial.
To do this I created a model and interface representing the ApiSettings section of my appsettings.json file:
"ApiSettings": {
"ApiBaseUrl": "https://example.com/api/",
"ApiVersion": "v1/"
}
The Model:
public class ApiSettings : IApiSettings
{
public string ApiBaseUri { get; set; }
public string ApiVersion { get; set; }
}
The Interface:
public interface IApiSettings
{
string ApiBaseUri { get; set; }
string ApiVersion { get; set; }
}
I then created a class that would be dependent on the service to inject the settings:
public class ApiSettingsBuilder
{
private readonly string _apiUri;
public ApiSettingsBuilder(IOptions<Configurator> config)
{
_apiUri = config.Value.ApiSettings.ApiBaseUrl +
config.Value.ApiSettings.ApiVersion;
}
public string ApiUri { get { return _apiUri; } }
}
The Problem: How do I create an new instance of this class?
public class ApiController : Controller
{
private readonly string _apiUri;
public ApiController()
{
ApiSettingsBuilder builder = new ApiSettingsBuilder(/*What do I do here*/);
_apiUri = builder.ApiUri;
}
public ApiController(IApiSettings settings)
{
//For testing
_apiUri = settings.ApiBaseUrl + settings.ApiVersion;
}
//...
}
Also, I know this is all a bit overkill, but I would still like an answer because It would possibly be useful in other scenarios.
You don't have to create new classes for unit testing purposes, you can mock the interface of your IOptions using appropriate framework, e.g. Moq:
var configurator = new Configurator() { ApiBaseUrl = "abc" };
var mock = new Mock<IOptions<Configurator>>();
mock.Setup(ap => ap.Value).Returns(configurator);
Then you can pass mocked object to your constructor for unit testing:
var controller = new ApiController(mock.Object);

Cannot mock .... The profiler must be enabled to mock, arrange or execute the specified target

I have the following in a test (my first ever JustMock test, I might add)...
var template = Mock.Create<MessageType>();
Mock.Arrange(() => template.Subject)
.Returns("This template has Zero tokens.");
Mock.Arrange(() => template.Body)
.Returns("This template has {{number}} of {{tokens}}.");
The class being Mocked looks like this ...
public class MessageType : BaseBusinessEntity
{
public string Body { get; set; }
public int DigestsToBeIncludedOn { get; set; }
public Guid MessageReference { get; set; }
public int MessageTypeId { get; set; }
public string Name { get; set; }
public int PredefinedRecipients { get; set; }
public string Subject { get; set; }
}
When I attempt to run the test I get ...
Error Message: Test method
Genesis.Service.Implementation.Tests.DigestFixture.ShouldCorrectlyExtractTemplateTokens
threw exception: Telerik.JustMock.Core.ElevatedMockingException:
Cannot mock 'System.String get_Subject()'. The profiler must be
enabled to mock, arrange or execute the specified target. Stacktrace:
at
Telerik.JustMock.Core.ProfilerInterceptor.ThrowElevatedMockingException(MemberInfo
member) at
Telerik.JustMock.Core.MocksRepository.CheckMethodInterceptorAvailable(IMatcher
instanceMatcher, MethodBase method) at
Telerik.JustMock.Core.MocksRepository.AddArrange(IMethodMock
methodMock) at
Telerik.JustMock.Core.MocksRepository.Arrange[TMethodMock](Expression
expr, Func1 methodMockFactory) at
Telerik.JustMock.Mock.<>c__DisplayClass81.b__6() at
Telerik.JustMock.Core.ProfilerInterceptor.GuardInternal[T](Func1
guardedAction) at Telerik.JustMock.Mock.Arrange[TResult](Expression1
expression) at
Genesis.Service.Implementation.Tests.DigestFixture.ShouldCorrectlyExtractTemplateTokens()
in
c:\Genesis\Development\Genesis.Service.Implementation.Tests\DigestFixture.cs:line
46
Can anyone point out what I've done wrong?
Be sure you have enabled the profiler from the menu.
While using Visual Studio for writing your tests you will notice the Telerik menu and the JustMock menu-item in it. Once there, you have to check if JustMock is enabled(“Enable JustMock” should be grey, see the example bellow).

Invalid column name error with EF 4.1 Code First

I've been having a problem with this for about a day now, I've searched and found similar problems with their solutions but haven't been able to fix this.
I've seen this done with the Teams example, so I'll do the same. I have a Team:
public abstract class Team
{
[Key]
public int IdTeam { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I also have a Match object:
public class Match
{
[Key]
public int IdMatch { get; set; }
[ForeignKey("HomeTeam")]
public int IdHomeTeam { get; set; }
[ForeignKey("AwayTeam")]
public int IdAwayTeam { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
Whenever I try to access the name of either team I get an Invalid column name Team_TeamId error. I'm guessing it has something to do with EF and the Foreign Keys not being mapped correctly. I've also seen other people use ICollections, but I don't think I need them for this case.
You have to fix this in the OnModelCreating method. Entity framework can't seem to recognize the foreign keys, so you have to specify it specifically.
public class Entities : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(b => b.AwayTeam)
.WithMany()
.HasForeignKey(b => b.IdAwayTeam);
modelBuilder.Entity<Match>()
.HasRequired(b => b.HomeTeam)
.WithMany()
.HasForeignKey(b => b.IdHomeTeam);
}
}
for more information about code first OnModelCreating check this: http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.onmodelcreating(v=vs.103).aspx

WCF DataContract With List of RegExs Won't Serialize Properly

I have a class that looks something like this:
[DataContract]
public class InboundMailbox
{
public const char EmailSeparator = ';';
[DataMember]
public string POP3Host { get; set; }
[DataMember]
public string EmailId { get; set; }
[DataMember]
public string WebServiceURL { get; set; }
[DataMember]
public List<Regex> Allowed { get; set; }
[DataMember]
public List<Regex> Disallowed { get; set; }
}
If Allowed and Disallowed are empty then it serializes just fine across my WCF service. As soon as one of those lists contains a value, I get this in a CommunicationException:
The socket connection was aborted. This could be caused by an error
processing your message or a receive timeout being exceeded by the
remote host, or an underlying network resource issue. Local socket
timeout was '00:00:29.9899990'.
Why is it giving me a hard time about serializing those two properties? Thanks in advance.
The Regex class implements the ISerializable interface, which means that it's serialized as a property bag (dictionary of string/object). Looking at the implementation of ISerializable.GetObjectData for the Regex class in Reflector, it shows that it serializes both the pattern (string) and the options (of type RegexOptions). Since the type is ISerializable, WCF doesn't know about RegexOptions, so it will fail to serialize this type.
One simple solution is to simply "tell" WCF that this is a known type, so the serialization will work (an easy place to declare it is using the [KnownType] attribute in the InboundMailbox class (see below). Another option would be to have the data member as the regex pattern instead of the Regex itself (and possibly the options as well).
public class StackOverflow_7909261
{
[DataContract]
[KnownType(typeof(RegexOptions))]
public class InboundMailbox
{
public const char EmailSeparator = ';';
[DataMember]
public string POP3Host { get; set; }
[DataMember]
public string EmailId { get; set; }
[DataMember]
public string WebServiceURL { get; set; }
[DataMember]
public List<Regex> Allowed { get; set; }
[DataMember]
public List<Regex> Disallowed { get; set; }
}
public static void Test()
{
MemoryStream ms = new MemoryStream();
InboundMailbox obj = new InboundMailbox
{
POP3Host = "popHost",
EmailId = "email",
WebServiceURL = "http://web.service",
Allowed = new List<Regex>
{
new Regex("abcdef", RegexOptions.IgnoreCase),
},
Disallowed = null,
};
DataContractSerializer dcs = new DataContractSerializer(typeof(InboundMailbox));
try
{
dcs.WriteObject(ms, obj);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
BTW, you'd find out the error if you had enabled tracing on the server side; it would have an exception saying that the type RegexOptions wasn't expected.

How to verify that method argument's property values are set when mocking methods with Moq?

Not sure if it has been asked before, here is the question.
Code first:
public class Customer {
public string Password { get; set; }
public string PasswordHash { get; set; }
}
public class CustomerService {
private ICustomerRepository _repo;
public CustomerService(ICustomerRepository repo) {
_repo = repo;
}
public int? AddCustomer(Customer customer) {
customer.PasswordHash = SHA1Hasher.ComputeHash(customer.Password);
return _repo.Add(customer);
}
}
public interface ICustomerRepository {
int? Add(Customer c);
}
public class CustomerRepository : ICustomerRepository {
int? AddCustomer(Customer customer) {
// call db and return identity
return 1;
}
}
[TestClass]
public class CustomerServiceTest {
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving() {
var repoMock = new Mock<ICustomerRepository>();
//how do I make sure the password hash was calculated before passing the customer to repository???
}
}
How do I verify that CustomerService assigned the PasswordHash before passing the customer to repository?
There are several approaches you could take. Although not necessarily the best solution, here's one that doesn't require you to change your existing API. It assumes that SHA1Hasher.ComputeHash is a public method.
[TestClass]
public class CustomerServiceTest
{
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving()
{
var customer = new Customer { Password = "Foo" };
var expectedHash = SHA1Hasher.ComputeHash(customer.Password);
var repoMock = new Mock<ICustomerRepository>();
repoMock
.Setup(r => r.Add(It.Is<Customer>(c => c.PasswordHash == expectedHash)))
.Returns(1)
.Verifiable();
// invoke service with customer and repoMock.Object here...
repoMock.Verify();
}
}
A slightly better solution would be to turn the SHA1Hasher into an injected service (such as IHasher) so that you can confirm that the PasswordHash property was assigned the value created by the IHasher instance.
Opening op your API even more, you could make the PasswordHash property virtual, so that you could pass a Mock Customer to the AddCustomer method to verify that the property was correctly set.
You could make SHA1Hasher non-static and virtual or wrap it in a ISHA1Hasher interface which can then be mocked. Wrapping static methods and objects in mockable classes is a classic way to increase testability.