I have two rules configured in NLog.config:
<logger name="Model" level="Info" writeTo="modelLog" final="true" />
<logger name="*" minlevel="Debug" writeTo="logFile" />
I am trying to write to the first one, using the following code:
LogEventInfo eventInfo = new LogEventInfo();
eventInfo.Level = LogLevel.Info;
eventInfo.LoggerName = "Model";
eventInfo.TimeStamp = DateTime.Now;
logger.Log(eventInfo);
But it keeps falling through to the second rule. I would have thought eventInfo.LoggerName = "Model"; would have sent it straight to the first rule?
Not at computer now so can't try your case, but I have a couple of questions.
Can you try using the "regular" logging functions (Info, Debug) and see if that works ad expected?
How did you resolve your logger? That is. What is "logger's" name?
If the actual logger's name is not "Model" my guess is that it won't meet the "Model" condition, even though you are passing "Model" in the Name field of the LogEventInfo.
[EDIT]
Here is an abbreviated example of a better NLog logger wrapper that could be used in the Ninject Logging Extension. This wrapper delegates logging calls to the underlying NLog logger in a way that preserves the call site information (class and method where logging request originated).
class NLogLogger : ILogger
{
private NLog.Logger logger;
//The Type that is passed in is ultimately the type of the current object that
//Ninject is creating. In the case of my example, it is Class1 and Class1 is
//dependent on ILogger.
public NLogLogger(Type t)
{
logger = NLog.LogManager.GetLogger(t.FullName);
}
//Trace, Warn, Error, Fatal eliminated for brevity
public bool IsInfoEnabled
{
get { return logger.IsInfoEnabled; }
}
public bool IsDebugEnabled
{
get { return logger.IsDebugEnabled; }
}
public void Info(string format, params object [] args)
{
if (logger.IsInfoEnabled)
{
Write(LogLevel.Info, format, args);
}
}
public void Debug(string format, params object [] args)
{
if (logger.IsDebugEnabled)
{
Write(LogLevel.Debug, format, args);
}
}
private void Write(LogLevel level, string format, params object [] args)
{
LogEventInfo le = new LogEventInfo(level, logger.Name, null, format, args);
logger.Log(typeof(NLogLogger), le);
}
}
Obviously this example does not deal with exceptions. However, I think that it illustrates the correct way to wrap NLog. It would be easy enough to implement the full Ninject Logging Extension ILogger interface, delegating each Info, Debug, Warn, etc call to a central Write method that would create the LogEventInfo class and then log it using the underlying NLog logger instance, passing in the type of the wrapping logger (typeof(NLogLogger) in my example). Passing the type of the wrapping logger is critical for maintaining call site info for your logging calls from your application code.
Based on NLog wrapper found in the Ninject Logging Extensions git repository.
More about dependency injection and named loggers (like NLog and log4net).
See my answer here for more about problems with naive logger wrappers.
Related
I want to test the method Utility#fromJson. In order to do that I need to mock the LoggerBean constructor which has some JNDI code in it.:
public class Utility {
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
private static ObjectMapper mapper = new ObjectMapper();
public static <T> T fromJson(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (IOException e) {
//during test log is null here
log.error("json deserialization failed", e);
}
return null;
}
}
In the following test class I can mock the constructor with mockito and want that mocked Logger should be present in the Utility class. However the log in the Utility class is null during the test.
class UtilityTest {
#Test
void testFromJson() throws Exception {
// mocking constructor
try (MockedConstruction<LoggerBean> mocked = Mockito.mockConstruction(LoggerBean.class, (mock, context) -> {
// further stubbings ...
when(mock.getLogger(getClass())).thenReturn(Logger.getLogger(getClass()));
})) {
// the logger here works
// Logger logger = Logger.getLogger(getClass());
//logger.info("-----------------");
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
I am using mockito-inline version 3.11.2.
Please suggest how to get the mocked log in the Utility class.
A distinct non-answer: don't even try.
If you really absolutely want a static method, then why not create a small utility class that does the same thing in a non static way (where you then can use the ctor of that class to insert your dependencies). And then maybe and keep a static instance of that class for your static method.
Remember that static comes with a lot of disadvantages. Especially in this case: if you can't test this static utility code without doing all this extra work, then you just introduced something that will interfere with unit testing any of the code that is going to use the static method.
In other words: you created hard to test code. Now you are facing the consequences of that, and your answer is to reach for the biggest hammer in the toolbox. But hammering a screw into the wall, yes that is possible, but is rarely a good idea. Instead you pick up a nail, or you go with the screw, but a screwdriver.
The real solution: step back, and remember to only only only ever use static for production code when doing so does not interfere with your ability to do proper, decent, simple unit testing.
Other readers: do not see this answer as discouragement to give the correct technical answer please!
So I finally realized that there is no need to mock the constructor of LoggerBean so that the following works:
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
So Mockito.mock(LoggerBean.class) already skips the call to the constructor.
class UtilityTest {
private static Logger log = LoggerBean.getLoggerBean().getLogger(UtilityTest.class);
#Test
void testFromJson() throws Exception {
try (MockedStatic<LoggerBean> mockedStaticLoggerBean = Mockito.mockStatic(LoggerBean.class)) {
LoggerBean loggerBeanMocked = Mockito.mock(LoggerBean.class);
when(loggerBeanMocked.getLogger(Utility.class)).thenReturn(pp);
mockedStaticLoggerBean.when(() -> LoggerBean.getLoggerBean()).thenReturn(loggerBeanMocked);
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
Now the Utility#fromJson will get the logger from UtilityTest class.
I am trying to inject the IApplicationConfigurationSection implementation into this MVC5 Controller, so that I can have access to some of the information (various strings) from my web.config custom section in all of my views:
public class BaseController : Controller
{
public IApplicationConfigurationSection AppConfig { get; set; }
public BaseController()
{
ViewBag.AppConfig = AppConfig; // AppConfig is always null
}
}
I want to use setter injection so I don't have to clutter up my derived Controller constructors with parameters that they don't really care about.
Note: If there is a better way to inject base class dependencies, please let me know. I admit I may not be on the right track here.
In my Global.asax I load my StructureMap configurations:
private static IContainer _container;
protected void Application_Start()
{
_container = new Container();
StructureMapConfig.Configure(_container, () => Container ?? _container);
// redacted other registrations
}
My StructureMapConfig class loads my registries:
public class StructureMapConfig
{
public static void Configure(IContainer container, Func<IContainer> func)
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver(func));
container.Configure(cfg =>
{
cfg.AddRegistries(new Registry[]
{
new MvcRegistry(),
// other registries redacted
});
});
}
}
My MvcRegistry provides the mapping for StructureMap:
public class MvcRegistry : Registry
{
public MvcRegistry()
{
For<BundleCollection>().Use(BundleTable.Bundles);
For<RouteCollection>().Use(RouteTable.Routes);
For<IPrincipal>().Use(() => HttpContext.Current.User);
For<IIdentity>().Use(() => HttpContext.Current.User.Identity);
For<ICurrentUser>().Use<CurrentUser>();
For<HttpSessionStateBase>()
.Use(() => new HttpSessionStateWrapper(HttpContext.Current.Session));
For<HttpContextBase>()
.Use(() => new HttpContextWrapper(HttpContext.Current));
For<HttpServerUtilityBase>()
.Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server));
For<IApplicationConfigurationSection>()
.Use(GetConfig());
Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());
}
private IApplicationConfigurationSection GetConfig()
{
var config = ConfigurationManager.GetSection("application") as ApplicationConfigurationSection;
return config; // this always returns a valid instance
}
}
I have also "thrown my hands up" and tried using the [SetterProperty] attribute on the BaseController - that technique failed as well.
Despite my best efforts to find a solution, the AppConfig property in my controller's constructor is always null. I thought that
`Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());`
would do the trick, but it didn't.
I have found that if I discard setter injection and go with constructor injection, it works as advertised. I'd still like to know where I'm going wrong, but I'd like to stress that I'm not a StructureMap guru - there may be a better way to avoid having to constructor-inject my base class dependencies. If you know how I should be doing this but am not, please share.
While constructor injection in this scenario appears to be the better solution to the stated problem as it follows The Explicit Dependencies Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
The mention of only needing to access the AppConfig in your views leads me to think that this is more of an XY problem and a cross cutting concern.
It appears that the controllers themselves have no need to use the dependency so stands to reason that there is no need to be injecting them into the controller explicitly just so that the dependency is available to the View.
Consider using an action filter that can resolve the dependency and make it available to the View via the same ViewBag as the request goes through the pipeline.
public class AccessesAppConfigAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var resolver = DependencyResolver.Current;
var appConfig = (IApplicationConfigurationSection)resolver.GetService(typeof(IApplicationConfigurationSection));
filterContext.Controller.ViewBag.AppConfig = appConfig;
}
}
This now makes the required information available to the views with out tight coupling of the controllers that may have a use for it. Removing the need to inject the dependency into derived classes.
Either via adorning Controller/Action with the filter attribute
[AccessesAppConfig] //available to all its actions
public class HomeController : Controller {
//[AccessesAppConfig] //Use directly if want to isolate to single action/view
public ActionResult Index() {
//...
return View();
}
}
or globally for all requests.
public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new AccessesAppConfigAttribute());
}
}
At this point it really does not matter which IoC container is used. Once the dependency resolver has been configured, Views should have access to the required information in the ViewBag
My aspect:
[Serializable]
class DumbLogger : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Log.Print("Entry: ") + args.Method.Name;
args.FlowBehavior = FlowBehavior.Continue;
}
}
This is what i am using to modify the calls in mscorlib AND trying to exclude them from being modified in my class called LOG
[assembly: MY_PROJECT.DumbLogger(
AttributeTargetTypes = "MY_PROJECT.Log",
AttributeExclude = true,
AttributePriority = 1)]
[assembly: MY_PROJECT.DumbLogger(
AttributeTargetAssemblies = "mscorlib",
AttributePriority = 2)]
But.. This doesnt do the trick because if i look at my LOG class with ILspy decompiler i can see method calls to any class # mscorlib.dll being modified for example:
<>z__Aspects.<System.Object.ToString>b__v(text)
The reason i wanna do this is because when i enter the method Log.Print it will generate a stackoverflow exception and will infinitely call itself.
I am already aware of maybe excluding certain namespaces and classes like string from mscorlib but i have my reasons to do it the way i described.
PostSharp Aspects in general are applied to declarations (assemblies, types, methods, parameters, fields, etc.). When you are applying an MethodLevelAspect (base class of OnMethodBoundaryAspect) on an external method, PostSharp transforms the call site (call instruction in IL), but still thinks of the aspect as being on the declaration itself.
There is currently no way to filter by call site and it would require a different kind of aspect and/or advices. Therefore your AttributeExclude=true specifying attribute on the assembly does not have any effect as it says that the aspect should not be applied on Log type, which it is not.
The common technique that solves exactly this case is to use a ThreadStatic variable to break the recursion cycle as the following code demonstrates:
[Serializable]
class DumbLogger : OnMethodBoundaryAspect
{
[ThreadStatic] private static bool logging;
public override void OnEntry(MethodExecutionArgs args)
{
if (logging)
return;
try
{
logging = true;
Log.Print("Entry: " + args.Method.Name);
args.FlowBehavior = FlowBehavior.Continue;
}
finally
{
logging = false;
}
}
}
Please also note that MethodInterception and OnMethodBoundary aspects are the only aspect that work on external assemblies.
I am new to Mockito as a concept. Can you please help me understand using Mockito for formhandlers in ATG. Some examples will be appreciated.
There is a good answer (related to ATG) for other similar question: using-mockito-for-writing-atg-test-case. Please review if it includes what you need.
Many of ATG-specific components (and form handlers particularly) are known to be "less testable" (in comparison to components developed using TDD/BDD approach), b/c design of OOTB components (including reference application) doesn't always adhere to the principle of having "Low Coupling and High Cohesion"
But still the generic approach is applicable for writing unit-tests for all ATG components.
Below is a framework we've used for testing ATG FormHandlers with Mockito. Obviously you'll need to put in all the proper bits of the test but this should get you started.
public class AcmeFormHandlerTest {
#Spy #InjectMocks private AcmeFormHandler testObj;
#Mock private Validator<AcmeInterface> acmeValidatorMock;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
private static final String ERROR1_KEY = "error1";
private static final String ERROR1_VALUE = "error1value";
#BeforeMethod(groups = { "unit" })
public void setUp() throws Exception {
testObj = new AcmeFormHandler();
initMocks(this);
}
//Test the happy path scenario
#Test(groups = { "unit" })
public void testWithValidData() throws Exception {
testObj.handleUpdate(requestMock, responseMock);
//Assume your formhandler calls a helper method, then ensure the helper method is called once. You verify the working of your helper method as you would do any Unit test
Mockito.verify(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
}
//Test a validation exception
#Test(groups = { "unit" })
public void testWithInvalidData() throws Exception {
Map<String, String> validationMessages = new HashMap<String, String>();
validationMessages.put(ERROR1_KEY, ERROR1_VALUE);
when(acmeValidatorMock.validate((AcmeInterface) Mockito.any())).thenReturn(validationMessages);
testObj.handleUpdate(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), ERROR1_VALUE);
}
//Test a runtime exception
#Test(groups = { "unit" })
public void testWithRunProcessException() throws Exception {
doThrow(new RunProcessException("")).when(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
testObj.handleAddGiftCardToCart(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), GENERAL_ERROR_KEY);
}
}
Obviously the above is just a framework that fit in nicely with the way in which we developed our FormHandlers. You can also add validation for redirects and stuff like that if you choose:
Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);
Ultimately the caveats of testing other people's code still applies.
Here's what I do when I unit test a form handler (at least until I manage to release a major update for AtgDust). Note that I don't use wildcard imports, so I'm not sure if this causes any namespace conflicts.
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import org.junit.*;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import atg.servlet.*;
import some.form.handler.FormHandler;
#RunWith(JUnit4.class)
public class FormHandlerTest {
#Mock DynamoHttpServletRequest request;
#Mock DynamoHttpServletResponse response;
FormHandler handler;
#Before
public void setup() {
initMocks(this);
handler = new FormHandler();
}
#Test
public void testSubmitHandlerRedirects() {
handler.handleSubmit(request, response);
verify(response).sendLocalRedirect(eq("/success.jsp"), eq(request));
assertThat(handler.getFormError(), is(false));
}
}
The basic idea is to set up custom behavior for mocks/stubs using when() on the mock object method invocation to return some test value or throw an exception, then verify() mock objects were invoked an exact number of times (in the default case, once), and do any assertions on data that's been changed in the form handler. Essentially, you'll want to use when() to emulate any sort of method calls that need to return other mock objects. When do you need to do this? The easiest way to tell is when you get NPEs or other runtime exceptions due to working with nulls, zeros, empty strings, etc.
In an integration test, ideally, you'd be able to use a sort of in-between mock/test servlet that pretends to work like a full application server that performs minimal request/session/global scope management. This is a good use for Arquillian as far as I know, but I haven't gotten around to trying that out yet.
In my project I've got a top-level abstract class FrameProducer. I added a slf4j logger at this level, so that every inheriting class already has it. Here the code:
public abstract class FrameProducer extends Observable {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected BufferedImage frame;
public BufferedImage getFrame() {
return frame;
}
public void fireEvent() {
logger.debug("Firing event. Implementing class: {}", this.getClass());
setChanged();
notifyObservers();
}
}
There are also two inheriting classes: CameraFrameGrabber and GrayscaleFilter. Yet, when the method fireEvent() is being called from CameraFrameGrabber or GrayscaleFilter the message is being logged at FrameProducer level. Here the log, for clarity:
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.CameraFrameGrabber
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.GrayscaleFilter
Is it possible to initialize the logger in FrameProducer in a way that everything gets logged at the most-specialized level in my class hierarchy?
Thanks for any help.
Edit: My log4j.properties looks like this:
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%C{1}.%M - %m%n
Logging in abstract classes is considered an anti-pattern by some because it introduces a potentially unexpected dependency. However if you are sure that all the stuff you are dealing with is your own that that's no problem I guess.
If you want to get the log message to show the concrete implementation rather than the abstract class name (which makes sense) then change your logging initialization statement in the abstract class to:
private final Logger logger = LoggerFactory.getLogger(getClass());
instead of something like:
private static final Logger logger = LoggerFactory.getLogger(MyAbstractClass.class);
i.e.
no static because it could be cast to something else.
getClass() instead of the specific class
Thanks for pointing out the right direction to look for possible corrections skaffman. I eventually changed my log4j.properties to (as one of the examples in the PatternLayout documentation says):
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-6r [%15.15t] %-5p %30.30c %x - %m%n
...and everything gets logged right.