I need a clarification about mocking tests. In my particular scenario, I have to test a service, that has the dependency on the connecting module, the connector. Basically what connector does, is that it creates an instance of the service call that has to be made. I will demonstrate on the example.
public DataService(Connector connector) {
this.connector = connector;
}
#Override
public ServiceData getWeatherData(String dataId) throws ServiceCommunicatonException {
try {
return connector.newGetWeatherDataCall().call(
WeatherData.builder().withId(dataId).build());
} catch (Exception e) {
throw new ServiceCommunicatonException(ERR_MSG);
}
}
So the connector.newGetWeatherDataCall() returns the instance of the type WeatherData.
Now, in order to test the Service, I guess I would need to mock the Connector. Mocking the Service is probably pointless, because then I am not really testing it, right?
I tried mocking the Connector with something like this:
#Before
public void setUp() {
connector = mock(Connector.class);
}
#Test
public void getDataTest() {
assertNotNull(service.getData("123"));
}
However, this is obviously wrong, because this gave ma NullPointerException because WeatherDataCall from this line: return
connector.newGetWeatherDataCall().call(
WeatherData.builder().withId(dataId).build()); was null.
So how should this be properly tested/mocked? It would be great with some code examples.
#Test
public void getDataTest() {
WeatherData getWeatherDataResponse = Mockito.mock(WeatherData.class);
when(connector.newGetWeatherDataCall()).thenReturn(getWeatherDataResponse);
when(getWeatherDataResponse.call(Matchers.any(Class.class))).thenReturn(new ServiceData());
assertNotNull(service.getData("123"));
}
Explanation:-
You got null because you did not set the expected return value. Actually connector.newGetWeatherDataCall() returns null. This is because you did not use Mockito.when() to return your expected results.
Second : In your case, a method on this return value is invoked so connector.newGetWeatherDataCall() should return a mock of WeatherData. And now you will set an expectation for weatherData.call(..) which will be ServiceData type.
You can also set up the mock to throw an exception, which is useful if the catch clause does a bit more work.
Related
I've been looking at forums all day trying to mock a class, but none of the solutions have worked for me, and I have no clue what I'm doing wrong (I'm new to Java testing).
I have this (renamed) class that I want to test, mainly each if condition to ensure they work:
public class MyClass {
public static List<Object> MyClass(#NotNull Session session, #NotNull MyObject updated, #NotNull Mode mode)
throws Exception {
ModeList modes = MyUtil.geModes(mode);
try {
final Transaction tr = updated.getTransaction();
MyObject original;
if(tr == null) {
original = new Foo().getCurrentBar(session, updated.getKey(), null, "en");
} else {
original = new Foo().getOtherBar(session,
updated.getKey(),
tr.getProp1().intValue(),
tr.getProp2().intValue(),
"en");
}
return SomeClass.check(updated, original, modes);
} catch (Exception ex) {
// handle
}
return null;
}
}
Please note I can't change this (or the Foo class) / add dependency injection, it needs to be tested as is. I have tried mockito, powerMock mock, mockStatic, partial mocks, etc, they all fail for one reason or another, and the real getCurrentBar / getOtherBar get called.
I may be getting tunnel vision at this point, but please advise.
This code is wrong, it should use a factory to get Foo, so you can mock the factory. But since you can't modify it then the next best thing is to use PowerMock.
You can follow this guide: https://github.com/powermock/powermock/wiki/MockConstructor make sure you do not forget the #RunWith and #PrepareForTest annotations.
I'm using Java 8 Functions and converters and have the following:
Main class
public final class MainClass {
public MainClass(
final Function<InputModel, OutputModel> businessLogic,
final Converter<Input, InputModel> inputConverter,
final Converter<OutputModel, Output> outputConverter) {
this.businessLogic = requireNonNull(businessLogic, "businessLogic is null.");
this.inputConverter = requireNonNull(inputConverter, "inputConverter is null.");
this.outputConverter = requireNonNull(outputConverter, "outputConverter is null.");
}
/**
* Request Handler.
*/
public Output handleRequest(final Input input) {
requireNonNull(input, "input is null.");
log.info("input request: {}", input);
try {
return inputConverter
.andThen(businessLogic)
.andThen(outputConverter)
.apply(input);
} catch (final Exception ex) {
throw new InternalServiceException(ex.getMessage(), ex);
}
}
}
Unit test
public final class TestClass {
#Mock
private Function<InputModel, OutputModel> mockedBusinessLogic;
#Mock
private Converter<Input, InputModel> mockedInputConverter;
#Mock
private Converter<OutputModel, Output> mockedOutputConverter;
private MainClass mainClass = new MainClass(mockedBusinessLogic, mockedInputConverter, mockedOutputConverter);
#Test
public void handleRequest_SHOULD_throwException_WHEN_inputConverter_throwsException() {
final RuntimeException inputConverterException = new NullPointerException(EXCEPTION_MESSAGE);
// what should I mock here? apply or convert.. apply for `Converter` seems to be deprecated.
when(mockedInputConverter.convert(input))
.thenThrow(inputConverterException);
final Exception exception = assertThrows(
InternalServiceException.class,
() -> mainClass.handleRequest(input)
);
assertThat(exception.getMessage(), is(EXCEPTION_MESSAGE));
assertThat(exception.getCause(), is(inputConverterException));
}
}
The above assertions fail.
I expect that if the inputConverter throws an exception, the catch block in handleRequest would wrap it to InternalServiceException, but it doesn't seem to be happening.
Any help?
How do I actually write unit tests for handleRequest method? I want to test the behavior when either of inputConveter, businessLogic or outputConveter throws exception.
Everything in your code is a mock. When you call andThen on your mocked inputConverter, then either null or a new mock instance is returned (depending on configuration). Each andThen will return a new instance with the chained converters (at least that is what I assume)
Make sure you mock all required methods, or better, use real objects instantiated from real classes.
Setting breakpoints and then debugging should help you find the issue. If you set in your try-block, and then single-step through the code, you will see that the way mocks are used in your code will not work. You could also save each result of andThen in a variable and then check in the debugger what type each has. I'm pretty sure it will either be null or "Mock for class X".
I have service calls in my application that make remote network calls to other services as well as DB calls. Spring Boot has good support for rolling back bad transactions with #Transactional, but I wanted to know if I could define a custom rollback procedure using an annotation.
I would need to rollback the data on the other services as well as the database.
In code, I could do it like this:
#Transactional
public void doSomethingComplicated() {
try {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
} catch(Exception e) {
srvcOne.rollBackNetworkCall();
}
}
but I was hoping I could do something like this:
#Transactional
#MyCustomRollbackListener(handler = MyCustomRollBackHandler.class)
public void doSomethingComplicated() {
srvcOne.makeRemoteNetworkCall();
srvcTwo.makeDatabaseCall();
}
and in the handler:
public class MyCustomRollBackHandler {
public void handleRollback() {
srvcOne.rollBackNetworkCall();
}
}
I implemented a global exception listener and I am able to get the class the exception came from, but I have no way to get the method and to retrieve any annotations on it. Here is my initial attempt:
#ControllerAdvice
public class RollbackExceptionListener{
private static final Logger logger = LoggerFactory.getLogger(RollbackExceptionListener.class);
#ExceptionHandler(Exception.class)
public void lookForAnnotationClassForException(final Exception exception) {
logger.error("Exception thrown", exception);
final StackTraceElement topElement = exception.getStackTrace()[0];
final Class callingClass = topElement.getClass();
final String methodName = topElement.getMethodName();
try {
// Can't get the method with just the name, need to
// know the params as well.
final Method method = callingClass.getMethod(methodName);
// Retrieve the annotation on the method and call the handler
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Is there anyway to do something like this?
Arguments are not part of the Stacktrace. If the method is unique, i.e. not overloaded, you can probably find it with getMethods()? Something else that comes to mind, maybe you can look at Aspects to wrap the method in some handler before it is executed. Can be done either at compile time or runtime.
The aspect can do the rollback itself, it can enrich the exception with the information you need, or it can set some ThreadLocal variable with the handler class that was defined in the method before re-throwing the exception. You can then get this value from the ThreadLocal at the point where you catch the exception.
Let's say that I have a some service class
class Service<T> {
T get(int id);
void save();
}
In my unit tests I mock both methods of this service using mockito. But there is a case when method save should be mocked based on mocked get method. For example if method get is called with an argument which is equal to 2 then method save should throw some exception.
I went through Mockito documentation but seems like have not found any solutions yet.
Any ideas how I can achieve this use case with Mockito?
1) what you are trying to do is calling a test case from from a test case.
2) Mocking is used mainly for testing the endpoint, may be for controllers.So if your save functions needs to called again or you have to reuse the code for other test case, you should do that, it has no problem.
But what you are saying is totally against the programming paradigms for mock test cases.
In my opinion needing a mocking like that should be avoided, but if you insist you can leverage the doAnswer() method for detailed mock handling.
Basically, you use two Answer instances. One that sets a flag when the method is called with 2, the other one resetting the flag.
Another answer reacts to that flag and throws an exception if needed.
private boolean throwExceptionNext;
#Test
public void test() {
Service mock = Mockito.mock(Service.class);
Mockito.doAnswer((__) -> {
throwExceptionNext = false;
return new Object();
}).when(mock).get(Mockito.anyInt());
Mockito.doAnswer((__) -> {
throwExceptionNext = true;
return new Object();
}).when(mock).get(2);
Mockito.doAnswer((__) -> {
if (throwExceptionNext)
throw new RuntimeException();
return null;
}).when(mock).save();
mock.get(3);
mock.save();
mock.get(2);
try {
mock.save();
Assert.fail();
} catch (RuntimeException e) {
}
mock.get(3);
mock.save();
}
I'm looking to combine the flexibility of Spring Profiles and Configurations with the parallel running of JUnit tests which utilize either the Parameterized or Theories annotation. Is there any way to incorporate all of these features to get my unit tests running?
The problem I keep running into is the parameters need access to an injected bean, which isn't possible since the function annotated with #Parameters or #DataPoints is supposed to be static. I'd really hate to have to wire that into each class or even a static function somewhere because I'd like to quickly be able to switch profiles without having to change Java code. Is this possible?
Found the ticket for this request. It seems the attached file has some issues though. Looks like it's been a feature request for quite some time now.
I've been looking for a solution of this problem too. And there is one ! But as it comes from somebody's blog, I can't take the credit for it however. :-)
Unfortunately I can't find the original blog any more...
#RunWith(Parameterized.class)
#ContextConfiguration("/beans.xml")
public class MyTest {
private final File file;
public MyTest(final File file) {
this.file = file;
}
#Autowired
private PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
#Parameterized.Parameters
public static Collection<File[]> getFilesToTest() throws Exception {
return getValidFiles();
}
#Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this); // does the autowiring !
}
#Test
public void testInTransactionContext() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(final TransactionStatus status) {
status.setRollbackOnly();
try {
... run the test ...
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
}