How to mock clock.millis() in Java - java

I have a code where I calculate the difference between current clock time and time saved in my db
If difference between the two is greater than certain value then I return result accordingly.
For this case I am trying to write test but is facing problem to mock Clock.millis(). I have referred some answers but none worked for me can someone help me with that.
For my test I want to mock this clock.millis() function with a fixed value so that each time I run test it takes that value only.

A Clock is meant for providing access to the current instant, date and time using a time-zone. You don't really need to mock it. As your class needs to obtain the current instant, so it should receive an instance of the Clock in the constructor:
public class FooService {
private final Clock clock;
public FooService(Clock clock) {
this.clock = clock;
}
public boolean isLocked() {
long differenceInSecond = (clock.millis() - this.getLockedAt()) / 1000;
return differenceInSecond < 7200;
}
private long getLockedAt() {
...
}
}
Then, in your test, you can use a fixed() clock, which will always return the same instant:
#Test
public void isLocked_shouldReturnTrue_whenDifferenceInSecondIsSmallerThan7200() {
// Create a fixed clock, which will always return the same instant
Instant instant = Instant.parse("2020-01-01T00:00:00.00Z");
Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
// Create a service instance with the fixed clock
FooService fooService = new FooService(clock);
// Invoke the service method and then assert the result
boolean locked = fooService.isLocked();
assertThat(locked).isTrue();
}
In a Spring Boot application, you could expose a Clock as a #Bean:
#Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
And then Spring will take care of injecting it into your service:
#Service
public class FooService {
private final Clock clock;
public FooService(Clock clock) {
this.clock = clock;
}
...
}

You need to wrap Clockinto your own class, exposing Clock.millis() as a delegate. In your test you can then mock your wrapper and return whatever you like.

Related

Control multiple clocks by changing it in one class

Is there a way to change the time in all classes by changing the clock in one class?
Say I have a test class A and a class B. I want to change the clock in the test class (A) so that it would automatically set B’s clock to the same time.
I Have tried hard coding the clocks in Both classes but it doesn’t really work for the test case I’m writing. Should I make a static clock class?
I think you could creating a singleton to share in your case tests.
Create any singleton to be shared
// this class can be any shared value
public class AnySingleton{
private static AnyClock clock;
public static AnyClock retrieveSingletonClock(){
if( clock == null ){
clock = new AnyClock();
}
return clock;
}
}
Use in tests
#ExtendWith(MockitoExtension.class)
class A {
private AnyClock anyClock;
#BeforeEach
public void init() {
this.anyClock = AnySingleton.retrieveSingletonClock();
}
...
}
#ExtendWith(MockitoExtension.class)
class B {
private AnyClock anyClock;
#BeforeEach
public void init() {
this.anyClock = AnySingleton.retrieveSingletonClock();
}
...
}
Note: Check if you really need associate unit tests because they should be treated on their own. Unit tests are different to integrated one.

Service in Spring not setting values with Junit

Im testing my service with Junit but the result is not the expected.
When i save my entity, the return date is not setted in service.
Test:
#Test
#DisplayName("Should set determined time for return date")
public void shouldSetReturnDate() {
ClientDTORequest dto = createNewDTOClient();
Client client = createNewClient();
Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client);
Client saved = clientService.save(dto);
Assertions.assertEquals(dateTimeNow.plusMinutes(30), saved.getReturnDate());
}
My createNewClient():
private Client createNewClient() {
//the null param is the return date
return new Client(1L, "name", null);
}
My service:
public Client save(ClientDTORequest dto) {
Client client = mapper.map(dto, Client.class);
client.setReturnDate(dateTimeNow.plusMinutes(30));
Client savedClient = clientRepository.save(client);
return savedClient;
}
And when the test result:
org.opentest4j.AssertionFailedError:
Expected :2022-04-04T01:17:25.715895900
Actual :null
The result is not passed by the service to mock, this is my shot, but i dont know why.
Thanks!
The problem is you're coupled to "now", so the service always will have the time at the moment it runs.
One of the best ways of work with time is by modeling the concept Clock or TimeProvider and injecting it to the Service. Then you can mock it to assert the time in the test.
class Clock {
LocalDateTime now() {
return LocalDateTime.now().plusMinutes(30); // <-- as you needs
}
}
class Service {
private Clock clock;
Service(Clock clock) {
this.clock = clock;
}
void save(MyEntity entity) {
entity.setCreatedDateTime(clock.now());
//repositoty.save(entity);
}
}
#Getter
class MyEntity {
private LocalDateTime createdDateTime;
public void setCreatedDateTime(LocalDateTime createdDateTime) {
//assing it to a field
this.createdDateTime = createdDateTime;
}
}
class ServiceTest {
#Mock
private Clock clock;
private Service service;
#Test
void testSave() {
LocalDateTime fixedDateTimeNow = LocalDateTime.of(2022, 4, 3, 18, 0, 0);
Mockito.when(clock.now()).thenReturn(fixedDateTimeNow);
MyEntity entity = new MyEntity();
service.save(entity);
Assertions.assertEquals(fixedDateTimeNow, entity.getCreatedDateTime());
}
}
Note: Be careful about holding state in your service, so it's not thread safe. So, you'll end up with concurrency problems when multiple calls to service occurs "at the same time".
If you injected your clientRepository with #Autowired then it won't mock. Try #SpyBean
(#Autowired ClientRepository clientRepository wouldn't mock; #SpyBean ClientRepository clientRepository should mock)
After some hours of testing i found the problem:
My service was changing data, but was overridden by my mock:
Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client); <-- mock overridden the changed data from service
Client saved = clientService.save(dto);
So i found ArgumentCaptor, where i can get the object from method call:
Declaring the Captor:
#Captor
ArgumentCaptor<Client> clientCaptor;
Using at test method:
Mockito.when(clientRepository.save(clientCaptor.capture())).thenReturn(client); //<-- capturing the result
clientService.save(dto);
Client saved = clientCaptor.getValue() //getting object
Assertions.assertEquals(dto.getReturnDate().plusMinutes(30), saved.getReturnDate()); //assertion

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 mock a Camel processor in a JUnit test

I have encountered a problem when I was tasked with creating JUnit test to one of my camel processor.
The main class is as follows: (redundant things omitted).
#Stateless
#Named
public class CalculateProportionalAmount implements Plugin{ // where Plugin is our interface extending a Processor
LocalDate now;
#Override
public void process(final Exchange exchange) throws Exception{
now = getNow();
int startDay = getValueOfInputParameter("start") //just gets 1-31 from input parameters on exchange
int value = getValueOfInputParameter("value") //gets value from input parameters
/*
More kind-of irrelevant lines of code. Idea is that the processor calculates number of days between "now" and startDay, calculates what proportion of month this amount of days is and applies this proportion to the value.
So if today would be 1st and startDay is 10th (so 10 days between) when September has 30 days and value = 1000, the processor would calculate (10/30)*1000
*/
}
public LocalDate getNow(){
return LocalDate.now();
}
}
And for the test class:
public class CalculateProportionalAmountTest{
Plugin plugin;
#Before
public void setUp(){
//inicialize parameter maps, instantiate the plugin, so that we can reference it. "plugin" value is then instance of the "CalculateProportionalAmount" class.
}
#Test
public void pluginTestNextMonth() throws Exception {
Mockito.when(((CalculateProportionalAmount) plugin).getNow()).thenReturn(LocalDate.of(2017, 12, 11)); //obviously does not work, because plugin is not mocked....
ruleParameter.put("start", "10"); //here we set the "start" param that processor class gets.
ruleParameter.put("value", "1000"); //here we set the "value" param that processor class gets.
Exchange prepareInput = prepareExchange(scenarioParameters, ruleParameter);
Exchange output = execute(prepareInput);
String resultString = getScenarioParameterByKey(output, "result");
TestCase.assertEquals(String.format("%.6f", Double.valueOf(1000) * 30 / 31), resultString); //obviously will not pass unless on 11th of December
}
}
My biggest problem is that the getNow() method is and has to be called inside the process method, overwriting any attempts to specify a date.
Calculating the "real" proportions is also not viable option as we need to be able to check for variants "later this month", "earlier this month" and "today" on any day.
As the most feasible solution I now have is to rig (mock) the getNow() method to return a specific date when called from the test, but I need to leave the process method to be working as written, without any mocks.
The project this is part of already uses Mockito, but I am not very skilled in how it works and how to correctly mock the class so that it works as described above. I already made an attempt to do so in the beginning of the test class, but it currently ends in exception and I have been browsing tutorials since without much luck.
Thank you for help
You can use #Spy i think.
#Spy
Plugin plugin;
And then in your test method you can manipulate with doReturn for this public method
Mockito.doReturn(LocalDate.of(2017, 12, 11)).when((CalculateProportionalAmount) plugin).getNow();
#Spy tag refer to real object and you can change the return methods of spy object.
Mockito offers partial mocks to mock methods like getNow and call the real implementation for other methods.
In order to test camel route properly you should extend CamelTestSupport class from camel package. In general, they provide a support for testing camel.
My advice is to create custom route:
#Override
protected RoutesBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
from( "direct:testRoute" )
.process( new YourPluginClass() )
.end();
}
};
}
Then, you will be able to call it with fluentTemplate from CamelTestSupport class and test processor properly.
In order to mock behaviour of processor (partially) use spy from Mockito as #drowny said. Keep it mind that if you want to use #Spy annotation you have to init it with MockitoAnnotations.initMocks(this) line in #Before set up method.

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