How to Mock a ZonedDateTime with Mockito and Junit - java

I need to mock a ZonedDateTime.ofInstant() method. I know there are many suggestions in SO but for my specific problem, till now I did not get any simple way out.
Here is my code :
public ZonedDateTime myMethodToTest(){
MyClass myClass;
myClass = fetchSomethingFromDB();
try{
final ZoneId systemDefault = ZoneId.systemDefault();
return ZonedDateTime.ofInstant(myClass.getEndDt().toInstant(), systemDefault);
} catch(DateTimeException dte) {
return null;
}
}
Here is my incomplete Test method :
#Mock
MyClass mockMyClass;
#Test(expected = DateTimeException.class)
public void testmyMethodToTest_Exception() {
String error = "Error while parsing the effective end date";
doThrow(new DateTimeException(error)).when(--need to mock here---);
ZonedDateTime dateTime = mockMyClass.myMethodTotest();
}
I want to mock the ZonedDateTime.ofInstant() method to throw a DateTimeException while parsing for the negative scenario. How I can do that.

As of now (18/03/2022) Mockito supports mocking static methods. You can do
#Test
public void testDate() {
String instantExpected = "2022-03-14T09:33:52Z";
ZonedDateTime zonedDateTime = ZonedDateTime.parse(instantExpected);
try (MockedStatic<ZonedDateTime> mockedLocalDateTime = Mockito.mockStatic(ZonedDateTime.class)) {
mockedLocalDateTime.when(ZonedDateTime::now).thenReturn(zonedDateTime);
assertThat(yourService.getCurrentDate()).isEqualTo(zonedDateTime);
}
}
Please note that you need to use mockito-inline dependency:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.4.0</version>
</dependency>

You cannot use Mockito for this because ZonedDateTime is a final class and ofInstant is a static method, but you can use the PowerMock library to enhance Mockito capabilities:
final String error = "Error while parsing the effective end date";
// Enable static mocking for all methods of a class
mockStatic(ZonedDateTime.class);
PowerMockito.doThrow(new DateTimeException(error).when(ZonedDateTime.ofInstant(Mockito.anyObject(), Mockito.anyObject()));

Related

NotAMockException exception when trying to verify a static method with Powermockito

I use PowerMock to test a static method as mentioned its documentation.
As far as I see, there may be a bug, but I am not sure:
Static mocking broken for Mockito >= 2.26.1
...
I tried the workarounds mentioned on the following pages, however it does not fix the problem and some of them cannot be applicable as they are outdated.
NotAMockException when trying to verify a static method
verifyStatic get NotAMockExcption from mockito
However, I get "Argument passed to verify() is of type Class and is not a mock!" error. Here is the service method that I am testing and test method:
service:
// I want to test this method
public CommandDTO create(EmployeeRequest request) {
// ...
log();
return CommandDTO.builder().uuid(employee.getUuid()).build();
}
private void log() {
LoggingUtils.info("Created...");
}
test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(LoggingUtils.class)
public class EMployeeServiceImplTest {
#Test
public void unit_test() {
// ...
PowerMockito.mockStatic(LoggingUtils.class);
employeeService.create(request);
PowerMockito.verifyStatic(LoggingUtils.class); // throws error
LoggingUtils.info(any());
}
}
Here are libraries and versions:
pom.xml:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>
Since you asked in another comment, here's a pattern I've used in the past to prevent the need for static mocking:
Imagine we have a static method...
public class SomeClass {
public static String doSomething(int x) { ... }
}
Now imagine our code using it like this...
public class MyClass {
public void someMethod() {
String xyz = SomeClass.doSomething(123);
...
}
}
If we now needed to mock that SomeStaticClass.doSomething(123) call, we need static mocking.
An alternative is a delegator:
public class MyDelegator {
public String doSomething(int x) {
return SomeClass.doSomething(x);
}
}
Now you can use that instead in your class:
public class MyClass {
private final MyDelegator myDelegator;
public MyClass(MyDelegator myDelegator) { this.myDelegator = myDelegator; }
public void someMethod() {
String xyz = myDelegator.doSomething(123);
...
}
}
And voila, you can simply mock the MyDelegator object instead of having to care that the original implementation was a static call.
Of course, this doesn't solve the underlying code smell, but it can help you to work around it in cases where you cannot refactor the static code itself.
Let me suggest a different approach altogether because I see you already use Mockito version 3.4.6 .
Since Mockito >= 3.4.0 you are able to mock static methods directly. This means you can completely get rid of the PowerMock dependency.
Also, AFAIK PowerMock does not support JUnit5. This solution will allow you to upgrade your JUnit test framework to version 5 without issues which I also highly recommend.
Static mocking using Mockito does require you to use the mockito-inline dependency over mockito-core but, because mockito-inline depends on mockito-core, Maven will also download the mockito-core package. Please note that the Mockito documentation states that, at one point in the future, they might abolish this package when they pull all these
"experimental" features to the core package.
Next to that, you should also replace #RunWith(PowerMockRunner.class) with #RunWith(MockitoJUnitRunner.class)
This is how you use it.
You can either define the mock per test method like so using a try-with-resources statement that automatically calls close
try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
// Call logic
}
Or you can define it for all tests in a #Before method because you use jUnit4.
private MockedStatic<Files> filesMock;
#Before
public void init() {
filesMock = org.mockito.Mockito.mockStatic(Files.class);
}
#After
public void teardown() {
filesMock.close();
}
#Test
void test() {
filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
}
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#mockito-inline
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks

JUnit Java Instant dependent tests

I'm using Instant.now() to get the current UTC millis, and then truncate it to the nearest hour. All my JUnit are failing because they are taking the current System time. How can I make Instant.now() return a fixed value which I could supply in the JUnit test.
public static Long getCurrentHour() {
Instant now = Instant.now();
Instant cH = now.truncatedTo(ChronoUnit.HOURS);
return cH.toEpochMilli();
}
You should mock the static method Instant.now() to give you a static instant value.
You can use PowerMockito for that.
#RunWith(PowerMockRunner.class)
#PrepareForTest(Instant.class)
public class TestClass {
#Mock private Instant mockInstant;
#Test
public void getCurrentHour() throws Exception {
PowerMockito.mockStatic(Instant.class);
when(Instant.now()).thenReturn(mockInstant);
when(mockInstant.truncatedTo(ChronoUnit.HOURS)).thenReturn(mockInstant);
long expectedMillis = 999l;
when(mockInstant.toEpochMilli()).thenReturn(expectedMillis);
assertEquals(expectedMillis, YourClass.getCurrentHour());
}
}

How to test business logic in method?

I have such method in my service layer:
public Long calculateItemsCostInShoppingCart(Long shoppingCartId) {
List<Item> items = shoppingCartRepository.findAllItems(shoppingCartId);
Long cost = 0L;
for (Item item : items) {
cost += item.getPrice();
}
return cost;
}
And I need to test calculation of summary cost of all items in list. I was thought about mockito, but it didn't work out cause mockito just create stubs, I need real entrance data and result based on them. How can do it?
// create mock
ShoppingRepository mock = mock(ShoppingRepository.class);
// define return value for method findAllItems()
when(mock.findAllItems()).thenReturn(listOf(...));
Here is an example how you can test it with Mockito:
public class SomeCalculatorTest {
#Mock
private ShoppingCartRepository shoppingCartRepository;
#InjectMocks
private SomeCalculator someCalculator = new SomeCalculator();
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testEmptyItemsList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(new ArrayList<>());
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(0L));
}
#Test
public void testOneItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(25L));
}
#Test
public void testTwoItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L), new ItemImpl(12L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(37L));
}
}
Assuming that you are developing a Java web application which runs on a application server another option might be to use Arquillian (http://arquillian.org/). In a nutshell, Arquillian is a framework which allows you to test you logic in environment it will run. But it might be some work to integrate Arquillian into your project. We are using Arquillian in several projects and it works well so far. Even the Persistence module which is an Alpha version works well.
And I need to test calculation of summary cost of all items in list.
In this case, you have to isolate the shoppingCartRepository dependency that doesn't perform any calculation.
I need real entrance data and result based on them. How can do it?
It describes an integration test. In this case, don't use Mockito.
To unit test :
You have to mock the dependency and you also need a way to set it in the instance of the class under test.
A constructor is often a fine way (let calling the class under test MyService):
public MyService(ShoppingCartRepository shoppingCartRepository){
this.shoppingCartRepository = shoppingCartRepository;
}
Then, in the test you should mock ShoppingCartRepository, record a behavior for findAllItems() and pass the mock in the constructor of MyService.
#Mock
private ShoppingCartRepository shoppingCartRepositoryMock;
#Test
public void calculateItemsCostInShoppingCart(){
Long cartId = Long.valueOf(123);
// set the dependency
MyService myService = new MyService(shoppingCartRepositoryMock);
// create the mock
Mockito.when(shoppingCartRepositoryMock.findAllItems(cartId))
.thenReturn(createMockedItems());
//action
Long actualCost = myService.calculateItemsCostInShoppingCart(cartId);
// assertion
Assert.assertEquals(expectedCost, actualCost);
}
private List<Item> createMockedItems() { ... }
You can use Rest assured library for test
get Rest assured response Object, and call method for method object of list.
#BeforeClass
public static void init() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
}
#Test
public void testUserRegistration() {
Response response =
RestAssured
.given()
.get(URL_LOGIN)
.then()
.assertThat()
.statusCode(200);
Assert.assertThat(200, Matchers.is(200));
Assert.assertThat(response.getStatusCode(), Matchers.is(200));
}

how to unit test method using "Spring Data JPA" Specifications

I was playing with org.springframework.data.jpa.domain.Specifications, it's just a basic search :
public Optional<List<Article>> rechercheArticle(String code, String libelle) {
List<Article> result = null;
if(StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(libelle)){
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
}else{
if(StringUtils.isNotEmpty(code)){
result= articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)));
}else{
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteLibelle(libelle)));
}
}
if(result.isEmpty()){
return Optional.empty();
}else{
return Optional.of(result);
}
}
And that's actually working fine but I'd like to write unit tests for this method and I can't figure out how to check specifications passed to my articleRepository.findAll()
At the moment my unit test looks like :
#Test
public void rechercheArticle_okTousCriteres() throws FacturationServiceException {
String code = "code";
String libelle = "libelle";
List<Article> articles = new ArrayList<>();
Article a1 = new Article();
articles.add(a1);
Mockito.when(articleRepository.findAll(Mockito.any(Specifications.class))).thenReturn(articles);
Optional<List<Article>> result = articleManager.rechercheArticle(code, libelle);
Assert.assertTrue(result.isPresent());
//ArgumentCaptor<Specifications> argument = ArgumentCaptor.forClass(Specifications.class);
Mockito.verify(articleRepository).findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
//argument.getValue().toPredicate(root, query, builder);
}
Any idea?
I was having almost the same problems as you had, and I changed my class that contains Specifications to be an object instead of just one class with static methods. This way I can easily mock it, use dependency injection to pass it, and test which methods were called (without using PowerMockito to mock static methods).
If you wanna do like I did, I recommend you to test the correctness of specifications with integration tests, and for the rest, just if the right method was called.
For example:
public class CdrSpecs {
public Specification<Cdr> calledBetween(LocalDateTime start, LocalDateTime end) {
return (root, query, cb) -> cb.between(root.get(Cdr_.callDate), start, end);
}
}
Then you have an integration test for this method, which will test whether the method is right or not:
#RunWith(SpringRunner.class)
#DataJpaTest
#Sql("/cdr-test-data.sql")
public class CdrIntegrationTest {
#Autowired
private CdrRepository cdrRepository;
private CdrSpecs specs = new CdrSpecs();
#Test
public void findByPeriod() throws Exception {
LocalDateTime today = LocalDateTime.now();
LocalDateTime firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
List<Cdr> cdrList = cdrRepository.findAll(specs.calledBetween(firstDayOfMonth, lastDayOfMonth));
assertThat(cdrList).isNotEmpty().hasSize(2);
}
And now when you wanna unit test other components, you can test like this, for example:
#RunWith(JUnit4.class)
public class CdrSearchServiceTest {
#Mock
private CdrSpecs specs;
#Mock
private CdrRepository repo;
private CdrSearchService searchService;
#Before
public void setUp() throws Exception {
initMocks(this);
searchService = new CdrSearchService(repo, specs);
}
#Test
public void testSearch() throws Exception {
// some code here that interact with searchService
verify(specs).calledBetween(any(LocalDateTime.class), any(LocalDateTime.class));
// and you can verify any other method of specs that should have been called
}
And of course, inside the Service you can still use the where and and static methods of Specifications class.
I hope this can help you.
If you are writing Unit Tests then you should probably mock the call to findAll() method of articleRepository Class using a mocking framework like Mockito or PowerMock.
There is a method verify() using which you can check if the mock is invoked for the particular parameters.
For Example, if you are mocking the findAll() method of articleRepository Class and want to know if this method is called with particular arguments then you can do something like:
Mokito.verify(mymock, Mockito.times(1)).findAll(/* Provide Arguments */);
This will fail the test if mock has not been called for the arguments that you provided.
Your problem is that you are doing too many things within that one method. You should have three different methods that work on articleRepository.
Then you can use mocking as the others suggest:
setup your mocks so that you know which call on articleRepository should be made
verify that exactly the expected calls are happening
Please note: these three methods should be internal; the main point there is: you can't test this method with ONE call from the outside; as it is doing more than one thing, depending on the input that you provide. Thus you need to create at least one test method for each of the potential paths in your code. And that becomes easier (from a conceptual point of view) when you separate your code into different methods.

java: how to mock Calendar.getInstance()?

In my code I have something like this:
private void doSomething() {
Calendar today = Calendar.getInstance();
....
}
How can I "mock" it in my junit test to return a specific date?
You can mock it using PowerMock in combination with Mockito:
On top of your class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassThatCallsTheCalendar.class})
The key to success is that you have to put the class where you use Calendar in PrepareForTest instead of Calendar itself because it is a system class. (I personally had to search a lot before I found this)
Then the mocking itself:
mockStatic(Calendar.class);
when(Calendar.getInstance()).thenReturn(calendar);
As far as I see it you have three sensible options:
Inject the Calendar instance in whatever method/class you set that day in.
private void method(final Calendar cal)
{
Date today = cal.getTime();
}
Use JodaTime instead of Calendar. This is less an option and more a case of a suggestion as JodaTime will make your life a lot easier. You will still need to inject this time in to the method.
DateTime dt = new DateTime();
Date jdkDate = dt.toDate();
Wrap Calendar inside some interface that allows you to fetch the time. You then just mock that interface and get it to return a constant Date.
Date today = calendarInterfaceInstance.getCurrentDate()
Don't mock it - instead introduce a method you can mock that gets dates. Something like this:
interface Utility {
Date getDate();
}
Utilities implements Utility {
public Date getDate() {
return Calendar.getInstance().getTime();
}
}
Then you can inject this into your class or just use a helper class with a bunch of static methods with a load method for the interface:
public class AppUtil {
private static Utility util = new Utilities();
public static void load(Utility newUtil) {
this.util = newUtil;
}
public static Date getDate() {
return util.getDate();
}
}
Then in your application code:
private void doSomething() {
Date today = AppUtil.getDate();
....
}
You can then just load a mock interface in your test methods.
#Test
public void shouldDoSomethingUseful() {
Utility mockUtility = // .. create mock here
AppUtil.load(mockUtility);
// .. set up your expectations
// exercise the functionality
classUnderTest.doSomethingViaAPI();
// ... maybe assert something
}
See also Should you only mock types you own? and Test smell - everything is mocked
Using Mockito and PowerMockito:
Calendar endOfMarch = Calendar.getInstance();
endOfMarch.set(2011, Calendar.MARCH, 27);
PowerMockito.mockStatic(Calendar.class);
Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch);
Refer to the link for the complete code.
Write a class called DateHelper with a method getCalendar that returns Calendar.getInstance(). Refactor the class that you're testing so that it has a member variable of type DateHelper, and a constructor that injects that member variable. Use that constructor in your test, to inject a mock of DateHelper, in which getCalendar has been stubbed to return some known date.
You can mockit using JMockit. Here you can see how you can do it: Mock Java Calendar - JMockit vs Mockito.
Avoid use Calendar.getInstance() and just use Mockito methods to return what you like.
For example:
#Test
fun italianLocale_returnsItalianFormatDate() {
val calendar: Calendar = Mockito.mock(Calendar::class.java)
Mockito.`when`(calendar.get(Calendar.DAY_OF_MONTH)).thenReturn(27)
Mockito.`when`(calendar.get(Calendar.YEAR)).thenReturn(2023)
Mockito.`when`(calendar.get(Calendar.MONTH)).thenReturn(1)
val formatted = calendar.toReadableDate()
assert(formatted == "27/01/2023")
}
import Mockito in your gradle file with:
testImplementation ("org.mockito.kotlin:mockito-kotlin:x.x.x")
or (if you are using groovy)
testImplementation "org.mockito.kotlin:mockito-kotlin:x.x.x"

Categories

Resources