Is it possible/easy to mock NLog log methods, using Rhino Mocks or similar?
Using Nuget : install-package NLog.Interface
Then: ILogger logger = new LoggerAdapter([logger-from-NLog]);
You can only mock virtual methods. But if You create some interface for logging and then implement it using NLog You can use dependency injection and in Your tests use mocked interface to see if system under test (SUT) is logging what You expect it to log.
public class SUT
{
private readonly ILogger logger;
SUT(ILogger logger) { this.logger = logger;}
MethodUnderTest() {
// ...
logger.LogSomething();
// ...
}
}
// and in tests
var mockLogger = new MockLogger();
var sut = new SUT(mockLogger);
sut.MethodUnderTest();
Assert.That("Expected log message", Is.Equal.To(mockLogger.LastLoggedMessage));
The simple answer, is 'no'. Looking at the code, dependency-injection is not supported, which seems rather an oversight, especially as it doesn't look difficult to implement (at first glance).
The only interfaces in the project are there to support COM interop objects and a few other things. The main Logger concrete class neither implements an interface, nor provides virtual methods.
You could either provide an interface yourself, or use Moles/TypeMock/ another isolation framework to mock the dependency.
I've used code like this to stub out the NLog logging code. You can make use of NLog's MemoryTarget which just keeps messages in memory until it's disposed of. You can query the content of the log using Linq or whatever (this example uses FluentAssertions)
using FluentAssertions
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NLog;
using NLog.Config;
using NLog.Targets;
...
private MemoryTarget _stubLogger;
[TestInitialize]
public void Setup()
{
ConfigureTestLogging();
}
protected virtual LoggingConfiguration GetLoggingConfiguration()
{
var config = new NLog.Config.LoggingConfiguration();
this._stubLogger = new MemoryTarget();
_stubLogger.Layout = "${level}|${message}";
config.AddRule(LogLevel.Debug, LogLevel.Fatal, this._stubLogger);
return config;
}
protected virtual void ConfigureTestLogging()
{
var config = GetLoggingConfiguration();
NLog.LogManager.Configuration = config;
}
[TestMethod]
public void ApiCallErrors_ShouldNotThrow()
{
// arrange
var target = new Thing();
// act
target.DoThing();
// assert
this._stubLogger.Logs.Should().Contain(l =>
l.Contains("Error|") &&
l.Contains("Expected Message"));
}
Related
I'm building up a .net core web app that requires background tasks to be run. To avoid using an external cron triggers we've decided to go with Hangfire; which is a beautiful package to use, does exactly whats needed then gets out of the way ;-)
To keep things clean I'm trying to stick to Uncle Bob's Clean architecture principles and seperate my ApplicationCore from the Infrastructure as much as possible. As Hangfire is an implementation detail it should ideally sit in the Infrastructure project, alongside database access, message queues, etc. with an Interface in the ApplicationCore, that my domain can use.
For the basic client running recurring and background jobs this has been fairly simple to do, and I've ended up with this as my Interface
namespace ApplicationCore.Interfaces
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
public interface IBackgroundJobClient
{
void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression);
void RemoveIfExists(string recurringJobId);
}
}
Implementation is a simple wrapper for these methods which uses RecurringJob
namespace Infrastructure.BackgroundJobs
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Hangfire;
using IBackgroundJobClient = ApplicationCore.Interfaces.IBackgroundJobClient;
public class HangfireBackgroundJobClient : IBackgroundJobClient
{
public void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression)
{
RecurringJob.AddOrUpdate<T>(recurringJobId, methodCall, cronExpression);
}
public void RemoveIfExists(string recurringJobId)
{
RecurringJob.RemoveIfExists(recurringJobId);
}
}
The issue that I have is needing to setup a RecurringJob with a supplied cancellationToken. However, I can't see an easy way to do this without exposing the underlying IJobCancellationToken and JobCancellationToken objects in my ApplicationCore code...?
What I've got at present is a wrapper for the JobCancellationToken in my Infrastructure.
namespace Infrastructure.BackgroundJobs
{
public class BackgroundJobCancellationToken : JobCancellationToken
{
public BackgroundJobCancellationToken(bool canceled): base(canceled)
{
}
}
}
An Interface in my ApplicationCore, which replicates the Hangfire one.
namespace ApplicationCore.Interfaces
{
using System.Threading;
public interface IJobCancellationToken
{
CancellationToken ShutdownToken { get; }
void ThrowIfCancellationRequested();
}
}
This is then used by the Method I want to execute as job, making use of the cancellationToken.ShutdownToken to pass into other methods requiring a cancellationToken.
public async Task GenerateSubmission(Guid SetupGuidId, IJobCancellationToken cancellationToken)
{
try
{
// Sort out the entities that we'll need
var setup = await this.SetupRepository.GetByGuidIdAsync(SetupGuidId);
var forecast = await this.GetCurrentForecastForSetup(setup, DateTime.UtcNow, cancellationToken.ShutdownToken);
// Other Code
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Which in turn is enabled elsewhere by calling
public async Task<Setup> EnableSetup(Setup setup)
{
setup.Enable();
this.jobClient
.AddOrUpdate<IForecastService>(
setup.GuidId.ToString(),
f => f.GenerateSubmission(setup.GuidId, null),
"45 */2 * * *");
await this.setupRepository.UpdateAsync(setup);
return setup;
}
This should be done with DomainEvents and Handlers, but one step at a time :-)
Is there a cleaner, better, easier way of doing this without taken a direct dependency on Hangfire in my ApplicationCore?
If the above setup works, I'll leave a comment on this question.
Since Hangfire 1.7 you no longer have to rely on IJobCancellationToken. You can simply use the standard .NET CancellationToken instead.
I'm using Ninject in a new Azure WebJobs project. One of my repositories requires a Db client to be passed. How do I pass this client?
My bindings class is:
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IMyRepository>().To<MyRepository>();
}
}
My Main function in the console app looks like this:
static void Main()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
var config = new Configuration();
config.AddJsonFile("appsettings.json");
DbClient _dbClient = new DbClient(config);
IMyRepository myRepository = kernel.Get<IMyRepository>(); // This is where I get an error
}
My repository code is like this which is expecting the DbClient
public class MyRepository : IMyRepository
{
private DbClient _client;
public MyRepository(DbClient client)
{
_client = client;
}
}
You need to setup a binding for your DbClient.
I'd suggest being cautious around when components are released. I've not seen a good ninject example for web jobs yet so I've wired up manually. But that's just my thoughts...
I want to Initialize a global Dictionary from Database in my web Api. Do i need to inject my DBContext in Global.Asax or Owin Startup. Any example would be much appreciated.
Any kind initialization purposes can be made in your custom defined OWIN Startup class class, like this:
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
[assembly: OwinStartup(typeof(WebAPIRestWithNest.Startup))]
namespace YourNamespace
{
public class Startup
{
public Dictionary<string, string> Table {get; private set;}
public void Configuration(IAppBuilder app)
{
// token generation
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(8),
Provider = new SimpleAuthorizationServerProvider()
});
// token consumption
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(WebApiConfig.Register());
Table = ... Connect from DB and fill your table logic ...
}
}
}
After that you can use your Startup.Table property from your application.
In general, it is bad practice to access objects using static field in the asp.net applications because this may lead to bugs that are hardly detected and reproduced: especially this is true for non-immutable/not-thread-safe objects like Dictionary.
I assume you want to cache some DB data in memory to avoid excessive SQL queries. It is good idea to use standard asp.net caching for this purpose:
public IDictionary GetDict() {
var dict = HttpRuntime.Cache.Get("uniqueCacheKey") as IDictionary;
if (pvtData==null) {
dict = doLoadDictionaryFromDB(); // your code that loads data from DB
HttpRuntime.Cache.Add(cacheKey, dict,
null, Cache.NoAbsoluteExpiration,
new TimeSpan(0,5,0), // cache at least for 5 minutes after last access
CacheItemPriority.Normal, null);
}
return dict;
}
This approach allows you to select appropriate expiration policy (without the need to reinventing the wheel with static dictionary).
If you still want to use static dictionary, you can populate it on the application start (global.asax):
void Application_Start(object sender, EventArgs e)
{
// your code that initializes dictionary with data from DB
}
Using asp.net identity RTW version.
I need to perform several actions in a transaction, including both UserMananger function calls and other operations on my DbContext (example: create new user, add it to group and perform some business-logic operations).
How should I do this?
My thoughts follow.
TransactionScope
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
// Do what I need
if (everythingIsOk) scope.Complete();
}
The problem is: UserManager functions are all async, and TransactionScope was not designed to work with async/await. It seems to be solved in .Net Framework 4.5.1. But I use Azure Web Sites to host my project builds, so I cannot target 4.5.1 yet.
Database transaction
public class SomeController : Controller
{
private MyDbContext DbContext { get; set; }
private UserManager<User> UserManager { get; set; }
public AccountController()
{
DbContext = new MyDbContext()
var userStore = new UserStore<IdentityUser>(DbContext);
UserManager = new UserManager<IdentityUser>(userStore);
}
public async ActionResult SomeAction()
{
// UserManager uses the same db context, so they can share db transaction
using (var tran = DbContext.Database.BeginTransaction())
{
try
{
// Do what I need
if (everythingIsOk)
tran.Commit();
else
{
tran.Rollback();
}
}
catch (Exception)
{
tran.Rollback();
}
}
}
}
That seems to work, but how can I unit-test it?
UserManager<> constructor accepts IUserStore<>, so I can easily stub it.
UserStore<> constructor accepts DbContext, no idea how I can stub this.
You can implement your own test user store that can be stubbed out for your unit test.
If you want to use the actual EF UserStore in your tests, that also will work, but it will be creating a database using the DefaultConnection string by default. You could specify a DatabaseInitializer to always drop/recreate your tables in your tests if you wanted to ensure a clean db for every test.
I wrote about this topic in another question.
However, I've since refactored my code to get rid of configuration access, thus allowing the specs to pass. Or so I thought. They run fine from within Visual Studio using TestDriven.Net. However, when I run them during rake using the mspec.exe tool, they still fail with a serialization exception. So I've created a completely self-contained example that does basically nothing except setup fake security credentials on the thread. This test passes just fine in TD.Net, but blows up in mspec.exe. Does anybody have any suggestions?
Update: I've discovered a work-around. After researching the issue, it seems the cause is that the assembly containing my principal object is not in the same folder as the mspec.exe. When mspec creates a new AppDomain to run my specs, that new AppDomain has to load the assembly with the principal object in order to deserialize it. That assembly is not in the same folder as the mspec EXE, so it fails. If I copied my assembly into the same folder as mspec, it works fine.
What I still don't understand is why ReSharper and TD.Net can run the test just fine? Do they not use mspec.exe to actually run the tests?
using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;
namespace MSpecTest
{
[Subject(typeof(MyViewModel))]
public class When_security_credentials_are_faked
{
static MyViewModel SUT;
Establish context = SetupFakeSecurityCredentials;
Because of = () =>
SUT = new MyViewModel();
It should_be_initialized = () =>
SUT.Initialized.ShouldBeTrue();
static void SetupFakeSecurityCredentials()
{
Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
}
static MyIdentity CreateIdentity()
{
return new MyIdentity(Environment.UserName, "None", true);
}
static MyPrincipal CreatePrincipal(MyIdentity identity)
{
return new MyPrincipal(identity);
}
}
public class MyViewModel
{
public MyViewModel()
{
Initialized = true;
}
public bool Initialized { get; set; }
}
[Serializable]
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public bool IsInRole(string role)
{
return true;
}
public IIdentity Identity
{
get { return _identity; }
}
}
[Serializable]
public class MyIdentity : IIdentity
{
private readonly string _name;
private readonly string _authenticationType;
private readonly bool _isAuthenticated;
public MyIdentity(string name, string authenticationType, bool isAuthenticated)
{
_name = name;
_isAuthenticated = isAuthenticated;
_authenticationType = authenticationType;
}
public string Name
{
get { return _name; }
}
public string AuthenticationType
{
get { return _authenticationType; }
}
public bool IsAuthenticated
{
get { return _isAuthenticated; }
}
}
}
Dan,
thank you for providing a reproduction.
First off, the console runner works differently than the TestDriven.NET and ReSharper runners. Basically, the console runner has to perform a lot more setup work in that it creates a new AppDomain (plus configuration) for every assembly that is run. This is required to load the .dll.config file for your spec assembly.
Per spec assembly, two AppDomains are created:
The first AppDomain (Console) is created
implicitly when mspec.exe is
executed,
a second AppDomain is created by mspec.exe for the assembly containing the specs (Spec).
Both AppDomains communicate with each other through .NET Remoting: For example, when a spec is executed in the Spec AppDomain, it notifies the Console AppDomain of that fact. When Console receives the notification it acts accordingly by writing the spec information to the console.
This communiciation between Spec and Console is realized transparently through .NET Remoting. One property of .NET Remoting is that some properties of the calling AppDomain (Spec) are automatically included when sending notifications to the target AppDomain (Console). Thread.CurrentPrincipal is such a property. You can read more about that here: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
The context you provide will run in the Spec AppDomain. You set Thread.CurrentPrincipal in the Because. After Because ran, a notification will be issued to the Console AppDomain. The notification will include your custom MyPrincipal that the receiving Console AppDomain tries to deserialize. It cannot do that since it doesn't know about your spec assembly (as it is not included in its private bin path).
This is why you had to put your spec assembly in the same folder as mspec.exe.
There are two possible workarounds:
Derive MyPrincipal and MyIdentity from MarshalByRefObject so that they can take part in cross-AppDomain communication through a proxy (instead of being serialized)
Set Thread.CurrentPrincipal transiently in the Because
(Text is required for formatting to work -- please ignore)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, for example, handles all the communication work for us. MSpec's ReSharper Runner can hook into the existing infrastructure (that, AFAIK, does not use .NET Remoting).