Expected custom exception in Junit 5 Assertions.assertThrows but nothing was thrown - mockito

Any chance that some one can enlighten me with where is the mistake?
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
EntryService service;
#InjectMocks
EntryController controller;
#Test
void testException() {
Mockito.when(service.addNewEntry(Mockito.any(EntryDTO.class))).thenThrow(new EntryNotFound("Entry not found"));
Assertions.assertThrows(EntryNotFound.class, () -> {
controller.saveNewEntry(new EntryDTO());
});
}
I'm getting:
org.opentest4j.AssertionFailedError: Expected com.example.exception.EntryNotFound to be thrown, but nothing was thrown.
Funnily enough, when I'm running the following test, everything seems to work just fine:
void testSuccess() {
Mockito.when(service.addNewEntry(Mockito.any(EntryDTO.class))).thenReturn(entry);
ResponseEntity<Entry> entry = controller.saveNewEntry(new EntryDTO());
Assertions.assertNotNull(entry);
Assertions.assertEquals(1l, entry.getBody().getId());
}

Just before sending the question I stumbled upon the answer. Since it has got my puzzled for a while I decide to share it in case it may be of any help to some one else.
Basically assertThrows() checks for exceptions that are not being already catched.
If I avoid catching the exception on:
controller.saveNewEntry(new EntryDTO()
then the test would have passed.

Related

How to mock the custom util class

How can I mock the custom util class? I am getting the error below:
[ERROR] 2019-08-20 12:06:02:197 [] com.metlife.api.clientlibrary.util.JWSRequestUtil.prepareRequestJWS():71 - Exception in preparing JWS request ::
java.lang.NullPointerException: null
The code is:
public class EPartnerPromotionHelperTest {
#InjectMocks
EPartnerPromotionHelper ePartnerPromotionHelper;
#Mock
private JWSRequestUtil jwsRequestUtil;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSavePromotion() throws Exception {
String loggerId = "loggerId";
PromotionDTO promotionDTO = new PromotionDTO();
promotionDTO.setDescription("description");
promotionDTO.setCreationDate(new Date());
promotionDTO.setModifiedDate(new Date());
Mockito.when(jwsRequestUtil.prepareRequestJWS(Matchers.any(EPartnerRestRequestDTO.class)
,Matchers.any(Boolean.class))).thenReturn("test");
PromotionDTO response =ePartnerPromotionHelper.savePromotion(loggerId,promotionDTO);
assertNotNull(response);
}
}
Assuming that the error message comes from the invocation of your prepareRequestJWS method, you can change your syntax and use doReturn instead.
Mockito.doReturn("test")
.when(jwsRequestUtil)
.prepareRequestJWS(Matchers.any(EPartnerRestRequestDTO.class),
Matchers.any(Boolean.class));
Writing it like this the prepareRequestJWS method won't be invoked, check the Overriding a previous exception-stubbing part that is described in the javadoc of the doReturn method. This also applies to normal methods that would throw Exception's when they are invoked.
However a question would be why this exception is coming from your JwsRequestUtil class in the first place. Feel free to add the relevant code to your question.

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.

log4net - LogicalThreadContext - and unit test cases

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!!

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.

How should I test null and/or empty string parameters in a method?

It is common to have classes with methods with string parameters that must be validated agains null or empty, such as this example:
public class MyClass {
public void MyMethod(string param){
if(string.IsNullOrEmpty(param)){
throw new ArgumentNullException(...);
}
//...
}
}
It's clear that the behavior of the method is the same for both (invalid) values. This is a very common situation, and when it comes to testing these methods, I always doubt about how to do it. I always create two separate tests for these cases:
[TestClass]
public class Tests {
[TestMethod]
public void MyMethod_should_fail_if_param_is_null(){
//...
myclass.MyMethod(null);
//...
}
[TestMethod]
public void MyMethod_should_fail_if_param_is_empty(){
//...
myclass.MyMethod("");
//...
}
}
But I see too much redundancy. Those tests are exactly the same, with the only difference being the parameter passed to the method. That bothers me very much, since I have to create two tests for each string parameter. A method with 3 parameters would have 6 tests only to test the parameters.
I think this is the right way of testing those parameters, but if I know that 99% of string parameters will be validated the same way, wouldn't it be better just test them for null (or empty) and assume that the behavior in the other case will be the same?
I would like to know what you think about this. I know what I'm asking is more a technical opinion than a technical question, but I think the testing community may have something interesting to say about this situation.
Thank you!
Personally I'd consider using a single test for all of the parameters. That doesn't follow the normal dogma of unit testing, but it increases the readability of the tests (by minimizing the amount of test code which is dedicated to a pretty repetitive case) and doesn't have much in the way of downsides. Yes, if the test fails you don't know whether all of the checks after the first failing one will also fail - but is that really a problem in practice?
The important point is to make sure that you've got a short cut for testing the case. For instance, you might write something like this (if your unit test framework doesn't have it already):
public static void ExpectException<T>(Action action) where T : Exception
{
try
{
action();
Assert.Fail("Expected exception " + typeof(T).Name);
}
catch (T exception)
{
// Expected
}
}
Then you can write:
[Test]
public void MyMethodFailsWithInvalidArguments()
{
ExpectException<ArgumentNullException>(() => myClass.MyMethod(null));
ExpectException<ArgumentException>(() => myClass.MyMethod(""));
}
Much more concise than doing each one with an individual try/catch block, or even using an ExpectedException attribute and multiple tests.
You might want overloads for cases where you also want to verify that in each case, no mocked objects have been touched (to check that side-effects are avoided) or possibly overloads for common exceptions like ArgumentNullException.
For single-parameter methods you could even write a method to encapsulate exactly what you need:
public void ExpectExceptionForNullAndEmptyStrings(Action<string> action)
{
ExpectException<ArgumentNullException>(() => action(null));
ExpectException<ArgumentException>(() => action(""));
}
then call it with:
[Test]
public void MyMethodFailsWithInvalidArguments()
{
// This *might* work without the
ExpectExceptionForNullAndEmptyStrings(myClass.MyMethod);
}
... and maybe another one for methods with a single parameter but a non-void return type.
That's possibly going a bit far though :)
If you use Java and JUnit you can use this syntax
#Test(expected = IllegalArgumentException.class)
public void ArgumentTest() {
myClass.MyMethod("");
myClass.MyMethod(null);
}

Resources