0

I have object

object func1{
   def something(arg1: Int): String{
    // var date = something2()
    // Using date
   }

   def something2(): LocalDate{
      LocalDate.now()
    }
}
  

I want to write a test on something method, How can I mock something2

Pawan Asipu
  • 29
  • 1
  • 8
  • 1
    You should pass the `now()` function in as a parameter, as @Dima suggested. But if you _must_ use and mock static methods, [PowerMock](https://github.com/powermock/powermock) will do it for you. I personally consider needing PowerMock a code smell, and avoid it. – Jack Leow Jan 24 '23 at 14:25
  • 1
    Does this answer your question? [How to test date created with LocalDateTime.now()](https://stackoverflow.com/questions/39527752/how-to-test-date-created-with-localdatetime-now) – stefanobaghino Jan 24 '23 at 15:23
  • No, I still not able write test – Pawan Asipu Jan 24 '23 at 16:30

2 Answers2

2

You can't make static methods. So, you need to do something like this:

def something(val now: () => Date = LocalDate.now) = ...

Then, in your production code, you do val foo = something() as you normally would, but in your test, you can do things like

something(_ => new Date(0l)) shouldBe foo

or

val date = mock[Function0[Date]]
when(date.apply()).thenReturn(new Date(0l))
something(date) shouldBe foo
Dima
  • 39,570
  • 6
  • 44
  • 70
  • Can you please explain bit more – Pawan Asipu Jan 24 '23 at 14:22
  • What's unclear? – Dima Jan 24 '23 at 14:31
  • something method in tests, how are mocking? In smoething method I have other parameters too. I am updating exactly in the question – Pawan Asipu Jan 24 '23 at 14:37
  • Pass other parameters in as well. It's ok to have several parameters. – Dima Jan 24 '23 at 14:39
  • something(_ => new Date(0l)) shouldBe foo In this line, Date(0l), in Date I can give LocalDate objeect right? And what should be my foo, expected value? – Pawan Asipu Jan 24 '23 at 14:45
  • The expected value should be the value you expect your function to return. You can use `LocalDate`, yeah ... but if you do, that kinda defeats the purpose of your question - nothing to "mock", your function is _already_ using `LocalDate`. – Dima Jan 24 '23 at 14:50
  • class func1 extends AnyFlatSpec with Matchers with MockFactory { "testing " should "be generated" in { val startOfMarch = LocalDate.of(2022, Month.MARCH, 1) something(_ => new Date(startOfMarch, int_value)) shouldBe "my expected answer" } } Would this work? – Pawan Asipu Jan 24 '23 at 14:51
  • No idea ... Try it :) – Dima Jan 24 '23 at 14:52
  • Can you please check the description once – Pawan Asipu Jan 24 '23 at 17:04
  • Sure. I can even check it twice! – Dima Jan 24 '23 at 17:19
0

If the code's functionality depends on the time, it's definitely recommended that you have a second look at the code you're testing and explicitly pass a Clock as a parameter or something along those lines (e.g. a function as suggested in other comments) to make its behavior easy to test.

If you are testing this to make sure that a field somewhere indeed contains the time returned by LocalDate.now() please consider that you might be testing the behavior of LocalDate rather than your own code's, so probably mocking that doesn't really give you anything.

If timing is fundamental to the function's behavior and you have no control over it, I believe you might somehow use Mockito's ability to mock static objects. I came up with the following which compiles, but I'm not sure about whether it works or not (since I believe it relies on some bytecode manipulation black magic which might make your testing suite brittle, so beware):

import scala.util.{Try, Using}
import java.time.{Clock, Instant, LocalDate, ZoneId}
import org.mockito.Mockito._

def withClock[A](clock: Clock)(f: => Unit): Try[Unit] = {
  Using(mockStatic(classOf[LocalDate])) { mocked =>
    mocked.when(() => LocalDate.now()).thenReturn(LocalDate.now(clock))
    f
  }
}

withClock(Clock.fixed(Instant.ofEpochMilli(42), ZoneId.of("UTC"))) {
  assert(LocalDate.now().toEpochDay() == 0)
}
stefanobaghino
  • 11,253
  • 4
  • 35
  • 63