log4net - LogicalThreadContext - and unit test cases - multithreading

I am starting to write a unit test (MS Test, with Resharper as the test runner). When I set the LogicalThreadContext (see below), my test cases get 'aborted'. Anybody know why? Is this related to the unit test being on a different thread? How do I resolve this?
[TestClass]
public class ContextInfoTest
{
private ILog _log;
[TestInitialize]
public void TestInitialize()
{
// logging configured in assembly.info
_log = LogManager.GetLogger(this.GetType());
}
[TestMethod]
public void FigureOutWhyAborting()
{
string input = "blah";
LogicalThreadContext.Properties["mypropertyname"] = input;
string output = LogicalThreadContext.Properties["mypropertyname"] as string;
Assert.AreEqual(input, output);
}
[TestMethod]
public void ThisWorks()
{
string input = "blah";
CallContext.LogicalSetData("mypropertyname", input);
string output = CallContext.LogicalGetData("mypropertyname") as string;
Assert.AreEqual(input, output);
}
The weird thing is that if I were to debug and step through the code, the Assert.AreEqual does get called and passes, so something is happening after that line of code... which is why I think it might have something to do with the test thread, etc.
Thanks!
UPDATE:
So I ran this test in MSTest and got this exception (Resharper didn't show it)
Unit Test Adapter threw exception:
Type is not resolved for member 'log4net.Util.PropertiesDictionary,log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'..
I'm using log4net v1.2.13, on VS2013, .Net 4.5.
This link seems to suggest it is a referenced assemblies problem, but there is no resolution. Any additional ideas would be greatly welcome, GAC'ing log4net is not an option.
https://issues.apache.org/jira/browse/LOG4NET-398

I ended up doing this to get it working:
put this in the TestCleanup() method:
CallContext.FreeNamedDataSlot("log4net.Util.LogicalThreadContextProperties");

So, I can't thank you enough for figuring this out to call FreeNamedDataSlot. This turned me on to my answer that worked for me. Instead of passing in the full namespace of the class, I just had to use the class name:
This was used somewhere deep in my Data Access Layer:
MySession session = (MySession)System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("MySession");
[TestCleanup]
public void Cleanup()
{
CallContext.FreeNamedDataSlot("MySession");
}
This worked perfect for me! Hopefully this helps someone else when using Visual Studio's Test environment.

I know this is a bit old but for the following worked for me.
Although log4net was referenced by my project and my unit tests, it was not configured in the unit test. Updating my ThreadContext helper to the following allowed my tests to succeed. If log4net is configured in your unit tests and you are still getting this issue you could key off a compilation symbol instead.
var is_configured = log4net.LogManager.GetRepository().Configured;
var props = is_configured
? (ContextPropertiesBase)LogicalThreadContext.Properties
: (ContextPropertiesBase)ThreadContext.Properties;
props[key] = value;

Thanks all for the tips, i try with:
[TestCleanup]
public void Cleanup()
{
CallContext.FreeNamedDataSlot("log4net.Util.LogicalThreadContextProperties");
}
And works!!

Related

Mockito.mockConstruction provides null logger in the tested class

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.

How can I run code in JUnit before Spring starts?

How can I run code in my #RunWith(SpringRunner.class) #SpringBootTest(classes = {...}) JUnit test before Spring starts?
This question has been asked several times (e.g. 1, 2) but was always "solved" by some configuration recommendation or other, never with a universal answer. Kindly don't question what I am about to do in that code but simply suggest a clean way to do it.
Tried so far and failed:
Extend SpringJUnit4ClassRunner to get a class whose constructor can run custom code before initializing Spring. Failed because super(testClass) must be called first thing and already does a whole lot of things that get in the way.
Extend Runner to get a class that delegates to SpringRunner instead of inheriting it. This class could run custom code in its constructor before actually instantiating the SpringRunner. However, this setup fails with obscure error messages like java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig. "Obscure" because my test has no web config and thus shouldn't meddle with sessions and cookies.
Adding an ApplicationContextInitializer that is triggered before Spring loads its context. These things are easy to add to the actual #SpringApplication, but hard to add in Junit. They are also quite late in the process, and a lot of Spring has already started.
One way to do it is to leave out SpringRunner and use the equivalent combination of SpringClassRule and SpringMethodRule instead. Then you can wrap the SpringClassRule and do your stuff before it kicks in:
public class SomeSpringTest {
#ClassRule
public static final TestRule TestRule = new TestRule() {
private final SpringClassRule springClassRule =
new SpringClassRule();
#Override
public Statement apply(Statement statement, Description description) {
System.out.println("Before everything Spring does");
return springClassRule.apply(statement, description);
}
};
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Test
public void test() {
// ...
}
}
(Tested with 5.1.4.RELEASE Spring verison)
I don't think you can get more "before" than that. As for other options you could also check out #BootstrapWith and #TestExecutionListeners annotations.
Complementing jannis' comment on the question, the option to create an alternative JUnit runner and let it delegate to the SpringRunner does work:
public class AlternativeSpringRunner extends Runner {
private SpringRunner springRunner;
public AlternativeSpringRunner(Class testClass) {
doSomethingBeforeSpringStarts();
springRunner = new SpringRunner(testClass);
}
private doSomethingBeforeSpringStarts() {
// whatever
}
public Description getDescription() {
return springRunner.getDescription();
}
public void run(RunNotifier notifier) {
springRunner.run(notifier);
}
}
Being based on spring-test 4.3.9.RELEASE, I had to override spring-core and spring-tx, plus javax.servlet's servlet-api with higher versions to make this work.

Mockito implemetation for formhandlers in ATG

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.

Unable to get default constructor for Integration class ninject

I'm new on using ninject and Dependency Injection, and have a problem using it.
I try to using Ninject on my class libray, and building an integration tests.
now, I see in many example that, for using ninject is just specified the DI Module like this:
Public Class DIModule : NinjectModule
public override void Load()
{
Bind<IUSAServices>().To<USAServices>();
}
And then on my test class, I try to call my dependency is like this:
[TestClass]
public class USAIntegrationTests
{
private readonly IUSAServices _usaService;
public USAIntegrationTests(IUSAServices usaServices)
{
_usaService = usaServices;
}
[TestMethod]
public void ValidateUserTests()
{
Assert.IsTrue(_usaService.ValidateUser("username1", "password1"));
}
}
And Getting this error:
Unable to get default constructor for class USATests.IntegrationTests.USAIntegrationTests.
However I read the documentation and tried like this:
[TestClass]
public class USAIntegrationTests
{
private readonly IUSAServices _usaService;
public USAIntegrationTests()
{
using (IKernel kernel = new StandardKernel(new DIModule()))
{
_usaService = kernel.Get<IUSAServices>();
}
}
[TestMethod]
public void ValidateUserTests()
{
Assert.IsTrue(_usaService.ValidateUser("mantab", "banget"));
}
}
The test is works properly.
My question is, why I getting that error? is that some way to get around it?
Thanks in advance.
Unit test frameworks require your test classes to have a default constructor. You usually can't integrate DI containers with them. Instead of using constructor injection, you will have to call the container directly from your code, although for unit tests you should typically not have a container at all (for integration tests however, this is okay).
You can add a paramterless constructor for the class. It worked for me.

Geb: setting the reports dir at runtime

I'm writing a little test framework for a site using Geb. As part of my reporting functionality, I'd like to be able to specify at runtime where the reportsDir lives. I'm no developer so please excuse any omissions in this question.
Everything I've read so far suggests that this can only be set via the project's configuration or the build adaptor. However, Geb's Configuration class has a setReportsDir method which I can access from my browser object:
def currentConfig = pageBrowser.getConfig()
def reportLocation = "target/runtime_reports_dir"
def reportFile = new File(reportLocation)
reportFile.mkdirs()
File newTarget = new File(reportLocation)
currentConfig.setReportsDir(newTarget)
Unfortunately, although this appears to change the reportsDir in the browser's config object, the actual output still appears in the directory defined by my configuration.
Is this possible? Could I override the setupReporting method in GebReportingTest instead (I've not found anything suggesting how this might be done either)?
--- Edit 1 ---
I've tried
class MyTest extends GebReportingTest {
def pageBrowser
def setup() {
this.pageBrowser = new Browser()
this.pageBrowser.config.reportsDir = new File( 'target/runtime_reports_dir' )
}
#Test
void runTestSet() {
setup()
this.pageBrowser....
}
}
after Tim's comments but I've had no joy so far. After invoking the setup() method, the pageBrowser's config object returns the reportsDir I've defined in code. However, all instances of the 'report' command store screenshots etc in the directory defined in GebConfig.groovy.
Geb will look for GebConfig.groovy in the root of the classpath
You can set reportsDir in there
See: http://www.gebish.org/manual/0.6.2/configuration.html#reports_dir
Edit:
Have you tried:
class MyTest extends GebReportingTest {
void setUp() {
browser.config.reportsDir = new File( 'target/runtime_reports_dir' )
}
#Test
void runTestSet() {
// Do testing
}
}

Resources