Live data from Hacker News

Six Years of Professional Clojure

engineering.nanit.com

131–140 of 254 posts

Re: Six Years of Professional Clojure

#131

Earlier quoted context omitted.

I think you are mistaken. Mocking and DI frameworks are two unrelated concepts. There is nothing in Java that forces you to use a DI framework, e.g., Spring if you want to use mocks during testing.

Let's say I have a class called User and in it a method that says the current time. So User#say_current_time which simply accesses the Date class (it takes no arguments). Can you show me how you would mock the current time of that method in Java? It's one line of Ruby/Javascript code to do that.

If you want to use DI, in java 8 you could inject a java.time.Clock instance in the constructor and provide a fixed instance at the required time in your test e.g.

    Instant testNow = ...
    User u = new User(Clock.fixed(testNow, ZoneOffset.UTC));
    u.sayCurrentTime();
although it would be better design to have sayCurrentTime take a date parameter instead of depending on an external dependency.

Re: Six Years of Professional Clojure

#132

Earlier quoted context omitted.

Let's say I have a class called User and in it a method that says the current time. So User#say_current_time which simply accesses the Date class (it takes no arguments). Can you show me how you would mock the current time of that method in Java? It's one line of Ruby/Javascript code to do that.

If you want to use DI, in java 8 you could inject a java.time.Clock instance in the constructor and provide a fixed instance at the required time in your test e.g. Instant testNow = ... User u = new User(Clock.fixed(testNow, ZoneOffset.UTC)); u.sayCurrentTime(); although it would be better design to have sayCurrentTime take a date parameter instead of depending on an external dependency.

Yes that was my point. You don't need DI or to structure your code any differently in Ruby/JS/Python. You just mock a method.

Re: Six Years of Professional Clojure

#133

Earlier quoted context omitted.

OK. first I could be ignorant about Java since I haven't touched it in more than a decade. Which library is doing that? And also what is mock(User.java) returning - is it an actual User instance or a stub? I want a real User instance (nothing mocked in it) with just the one method mocked. And again if this is possible I will admit ignorance and tip my hat at the Java guys.

It's Mockito [1], which has been a standard for a while. There are other libraries and they use different strategies to provide this kind of functionalities (dynamic proxies, bytecode weaving, annotation processing, etc...). [1] https://site.mockito.org/

And ... is the whole user being mocked or just the method?

Re: Six Years of Professional Clojure

#134

Earlier quoted context omitted.

I think you are mistaken. Mocking and DI frameworks are two unrelated concepts. There is nothing in Java that forces you to use a DI framework, e.g., Spring if you want to use mocks during testing.

Let's say I have a class called User and in it a method that says the current time. So User#say_current_time which simply accesses the Date class (it takes no arguments). Can you show me how you would mock the current time of that method in Java? It's one line of Ruby/Javascript code to do that.

I am assuming this is easier in Ruby because you can monkey patch classes?

Mockito in Java has a nifty way of doing this with Mockito.mockStatic:

  @Test
  public void mockTime() throws InterruptedException {
    LocalDateTime fake = LocalDateTime.of(2021, 7, 2, 19, 0, 0);

    try (MockedStatic call = Mockito.mockStatic(LocalDateTime.class)) {
      call.when(LocalDateTime::now).thenReturn(fake);

      assertThat(LocalDateTime.now()).isEqualTo(fake);
      Thread.sleep(2_000);
      assertThat(LocalDateTime.now()).isEqualTo(fake);
    }

    LocalDateTime now = LocalDateTime.now();
    assertThat(now).isAfter(fake);
    assertThat(now).isNotEqualTo(fake);
  }
Or you can pass a Clock instance and use .now(clock). That Clock then can be either a system clock or a fixed value.

Re: Six Years of Professional Clojure

#135

Earlier quoted context omitted.

If you want to use DI, in java 8 you could inject a java.time.Clock instance in the constructor and provide a fixed instance at the required time in your test e.g. Instant testNow = ... User u = new User(Clock.fixed(testNow, ZoneOffset.UTC)); u.sayCurrentTime(); although it would be better design to have sayCurrentTime take a date parameter instead of depending on an external dependency.

Yes that was my point. You don't need DI or to structure your code any differently in Ruby/JS/Python. You just mock a method.

In my experience the need to mock out individual methods like this is an indication that the code is badly structured in the first place. The time source is effectively a global variable so in this example you'd want to pass the time as a parameter to `sayCurrentTime` and avoid the need to mock anything in the first place. A lot of C#/java codebases do seem to make excessive use of mocks and DI in this way though.

Re: Six Years of Professional Clojure

#136

Earlier quoted context omitted.

User mock = mock(User.java) when(mock.say_current_time()).thenReturn(someDate)

OK. first I could be ignorant about Java since I haven't touched it in more than a decade. Which library is doing that? And also what is mock(User.java) returning - is it an actual User instance or a stub? I want a real User instance (nothing mocked in it) with just the one method mocked. And again if this is possible I will admit ignorance and tip my hat at the Java guys.

I think what you want is a "spy" (partial mock), not a full "mock", but yes, both are possible. You can partially mock classes, i.e., specific methods only. Syntax is almost the same, instead of mock(User.class) you write spy(User.class).

Re: Six Years of Professional Clojure

#137

Earlier quoted context omitted.

Can you elaborate why? To be honest, I don't have experience with large-scale Clojure codebases, but I have my fair share working on fairly hefty Python and Perl projects, and I tend to think that the parent commenter is mostly right. What makes you think they are incorrect?

Not who you are responding to, but the common idea that static types are all win and no cost has become very popular these days, but isn't true, it's just that the benefits of static typing are immediately apparent and obvious, but their costs are more diffuse and less obvious. I thought this was a pretty good write up on the subject that gets at a few of the benefits https://lispcast.com/clojure-and-types/ Just to n…

Your third point about having to encode everything isn’t quite true. Your example is just brittle in that it doesn’t allow additional values to show up causing it to break when they do. That’s not a feature of static type systems but how you wrote the code.

This blog post[1] has a good explanation about it, if you can forgive the occasional snarkyness that the author employs.

In a dynamic system you’re still encoding the type of the data, just less explicitly than you would in a static system and without all the aid the compiler would give you to make sure you do it right.

[1]: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ...

Re: Six Years of Professional Clojure

#138

Earlier quoted context omitted.

Can you elaborate why? To be honest, I don't have experience with large-scale Clojure codebases, but I have my fair share working on fairly hefty Python and Perl projects, and I tend to think that the parent commenter is mostly right. What makes you think they are incorrect?

Not who you are responding to, but the common idea that static types are all win and no cost has become very popular these days, but isn't true, it's just that the benefits of static typing are immediately apparent and obvious, but their costs are more diffuse and less obvious. I thought this was a pretty good write up on the subject that gets at a few of the benefits https://lispcast.com/clojure-and-types/ Just to n…

> In a language as open and flexible as Clojure, this information can pass through your application without issue. Clojure programs are able to be less fragile and coupled because of this.

Or this can wreak havoc :) Nothing stops you from writing Map or Map[Any, Any], right?

Re: Six Years of Professional Clojure

#139

Earlier quoted context omitted.

Let's say I have a class called User and in it a method that says the current time. So User#say_current_time which simply accesses the Date class (it takes no arguments). Can you show me how you would mock the current time of that method in Java? It's one line of Ruby/Javascript code to do that.

I am assuming this is easier in Ruby because you can monkey patch classes? Mockito in Java has a nifty way of doing this with Mockito.mockStatic: @Test public void mockTime() throws InterruptedException { LocalDateTime fake = LocalDateTime.of(2021, 7, 2, 19, 0, 0); try (MockedStatic call = Mockito.mockStatic(LocalDateTime.class)) { call.when(LocalDateTime::now).thenReturn(fake); assertThat(LocalDateTime.now()).isEqua…

> I am assuming this is easier in Ruby because you can monkey patch classes?

Yes, that was my point. I see it's possible in Java though, hurts my eyes a bit but possible :)

Re: Six Years of Professional Clojure

#140

Earlier quoted context omitted.

It's Mockito [1], which has been a standard for a while. There are other libraries and they use different strategies to provide this kind of functionalities (dynamic proxies, bytecode weaving, annotation processing, etc...). [1] https://site.mockito.org/

And ... is the whole user being mocked or just the method?

It creates a stub, but you can also configure it to pass any method calls to original implementation. You should be tiping your hat i think.

https://javadoc.io/static/org.mockito/mockito-core/3.11.2/or...

User mock = mock(User.java)

Should have been

User mock = mock(User.class)

Post reply on HN