I have a method:

public int checkQuality() { Calendar currentDate = Calendar.getInstance(); long differenceOne = this.expireDate.getTimeInMillis() - this.createDate.getTimeInMillis(); long differenceTwo = currentDate.getTimeInMillis() - this.createDate.getTimeInMillis(); return (int) (((float) differenceTwo / differenceOne) * 100); } 

It checks in percents on how much the expiration date of the goods is in percents, and returns int these percentages.

I need to test it and the first test looks like this:

 @Test public void whenThen() { Calendar createDate = new GregorianCalendar(2016, 11, 16); Calendar expireDate = new GregorianCalendar(2017, 11, 31); Product food = new Food(createDate, expireDate); ControlQuality control = new ControlQuality(); control.uploadInRepo(food); assertThat(food, is(control.getRepo().get(0).getProducts().get(0))); } 

It is obvious that in a couple of days he will not work. Of course, when creating Calendar objects, you can push off from the current date, but it seems to me to be some kind of crutch ... How can I make it always work without sticks, scrap, and other hand-made utensils?

  • one
    no matter how funny it is, make a CalendarProvider and pass it inside - etki
  • And how to do something, I do not understand ... - Pavel

1 answer 1

It is obvious that in a couple of days he will not work.

I would say that it is completely unobvious. Because it is not clear what kind of relationship this line is:

 assertThat(food, is(control.getRepo().get(0).getProducts().get(0))); 

It has to the checkQuality() method you checkQuality() but I suspect that your repository simply does not return rotten goods).

If you want to check the "progress of quality", then write the tests first to checkQuality() , and then add higher-level tests (if they are needed at all).

As for the date. One of the main provisions of unit testing is that we should / want to check only the code of the unit that we are testing. This means that we should not / do not want to check any other third-party code. Especially if this code requires preliminary complicated settings (for example, accessing the database) or “capricious” (current date). What is done with code that we don’t want to test? It is allocated depending on the current unit (read, class / method) and is mocked in the test (ie, we ourselves ask it the desired behavior).

Therefore, the easiest option is to pass Calendar currentDate externally, as well as expireDate and createDate . This can be implemented in the forehead - you transmit directly to the Calendar , and a workaround - with the transfer of some provider who will return the calendar. In the test, the behavior of this dependence, you will determine for yourself, achieving the desired result.

Yes, and another tip: the dates in the tests should not contain absolute values! Values ​​should be only relative, for example, сегодня - 7 дней , сегодня + 2 дня . Only in this way, tests related to dates will always work, not just today or tomorrow.

  • >>> Therefore, the easiest option is to transfer Calendar currentDate from the outside <<< What do you mean by "from outside" when it comes to initialization right during the test, that’s what it is. And if something else I did not understand you, please explain a little more in detail. - Pavel
  • checkQuality(Calendar currentDate) in the simplest case - like this: checkQuality(Calendar currentDate) . In a more complex way: new Food(expireDate, createDate, new CalendarProvider()) , and then inside checkQuality to receive: Calendar currentDate = calendarProvider.GetCalendar(); . - andreycha