Skip to content

Commit 38a61a9

Browse files
authored
Move from mockito to scalamock (RustedBones#62)
1 parent b02fcca commit 38a61a9

File tree

4 files changed

+97
-72
lines changed

4 files changed

+97
-72
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ lazy val `pekko-http-metrics-core` = (project in file("core"))
6464
Dependencies.PekkoHttp,
6565
Dependencies.Provided.PekkoStream,
6666
Dependencies.Test.Logback,
67-
Dependencies.Test.Mockito,
6867
Dependencies.Test.PekkoHttpTestkit,
6968
Dependencies.Test.PekkoSlf4j,
7069
Dependencies.Test.PekkoStreamTestkit,
70+
Dependencies.Test.ScalaMock,
7171
Dependencies.Test.ScalaTest
7272
)
7373
)

core/src/test/scala/fr/davit/pekko/http/metrics/core/HttpMetricsSpec.scala

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ import org.apache.pekko.http.scaladsl.server.{RequestContext, RouteResult}
2424
import org.apache.pekko.stream.scaladsl.Keep
2525
import org.apache.pekko.stream.testkit.scaladsl.{TestSink, TestSource}
2626
import org.apache.pekko.testkit.TestKit
27-
import org.mockito.ArgumentCaptor
28-
import org.mockito.ArgumentMatchers.any
29-
import org.mockito.Mockito.{mock, when}
27+
import org.scalamock.matchers.ArgCapture.CaptureOne
28+
import org.scalamock.scalatest.MockFactory
3029
import org.scalatest.BeforeAndAfterAll
3130
import org.scalatest.concurrent.ScalaFutures
3231
import org.scalatest.flatspec.AnyFlatSpecLike
@@ -38,23 +37,22 @@ class HttpMetricsSpec
3837
extends TestKit(ActorSystem("HttpMetricsSpec"))
3938
with AnyFlatSpecLike
4039
with Matchers
40+
with MockFactory
4141
with ScalaFutures
4242
with BeforeAndAfterAll {
4343

4444
implicit val ec: ExecutionContext = system.dispatcher
4545

46-
private def anyRequestContext() = any(classOf[RequestContext])
47-
private def anyRequest() = any(classOf[HttpRequest])
48-
4946
abstract class Fixture[T] {
50-
val metricsHandler: HttpMetricsHandler =
51-
mock(classOf[HttpMetricsHandler])
52-
val server: Function[RequestContext, Future[RouteResult]] =
53-
mock(classOf[Function[RequestContext, Future[RouteResult]]])
47+
val handler = mock[HttpMetricsHandler]
48+
val server = mockFunction[RequestContext, Future[RouteResult]]
49+
50+
(handler.onConnection _).expects().returns((): Unit)
51+
(handler.onDisconnection _).expects().returns((): Unit)
5452

5553
val (source, sink) = TestSource
5654
.probe[HttpRequest]
57-
.via(HttpMetrics.meterFlow(metricsHandler).join(HttpMetrics.metricsRouteToFlow(server)))
55+
.via(HttpMetrics.meterFlow(handler).join(HttpMetrics.metricsRouteToFlow(server)))
5856
.toMat(TestSink.probe[HttpResponse])(Keep.both)
5957
.run()
6058

@@ -97,80 +95,99 @@ class HttpMetricsSpec
9795
}
9896

9997
it should "call the metrics handler on handled requests" in new Fixture {
100-
val request: ArgumentCaptor[HttpRequest] = ArgumentCaptor.forClass(classOf[HttpRequest])
101-
val response: ArgumentCaptor[HttpResponse] = ArgumentCaptor.forClass(classOf[HttpResponse])
102-
when(metricsHandler.onRequest(request.capture()))
103-
.thenAnswer(_.getArgument(0))
98+
val request = CaptureOne[HttpRequest]()
99+
val response = CaptureOne[HttpResponse]()
100+
101+
(handler.onRequest _)
102+
.expects(capture(request))
103+
.onCall { (req: HttpRequest) => req }
104104

105-
when(server.apply(anyRequestContext()))
106-
.thenAnswer(invocation => complete(StatusCodes.OK)(invocation.getArgument[RequestContext](0)))
107-
when(metricsHandler.onResponse(anyRequest(), response.capture()))
108-
.thenAnswer(_.getArgument(1))
105+
server
106+
.expects(*)
107+
.onCall(complete(StatusCodes.OK))
109108

109+
(handler.onResponse _)
110+
.expects(*, capture(response))
111+
.onCall { (_: HttpRequest, resp: HttpResponse) => resp }
112+
113+
val expectedRequest = HttpRequest()
110114
sink.request(1)
111-
source.sendNext(HttpRequest())
115+
source.sendNext(expectedRequest)
112116
sink.expectNext()
113117

114118
source.sendComplete()
115119
sink.expectComplete()
116120

117-
val expected = Marshal(StatusCodes.OK)
121+
val expectedResponse = Marshal(StatusCodes.OK)
118122
.to[HttpResponse]
119123
.futureValue
120124

121-
response.getValue shouldBe expected
125+
request.value shouldBe expectedRequest
126+
response.value shouldBe expectedResponse
122127
}
123128

124129
it should "call the metrics handler on rejected requests" in new Fixture {
125-
val request: ArgumentCaptor[HttpRequest] = ArgumentCaptor.forClass(classOf[HttpRequest])
126-
val response: ArgumentCaptor[HttpResponse] = ArgumentCaptor.forClass(classOf[HttpResponse])
127-
when(metricsHandler.onRequest(request.capture()))
128-
.thenAnswer(_.getArgument(0))
130+
val request = CaptureOne[HttpRequest]()
131+
val response = CaptureOne[HttpResponse]()
132+
(handler.onRequest _)
133+
.expects(capture(request))
134+
.onCall { (req: HttpRequest) => req }
129135

130-
when(server.apply(anyRequestContext()))
131-
.thenAnswer(invocation => reject(invocation.getArgument[RequestContext](0)))
136+
server
137+
.expects(*)
138+
.onCall(reject)
132139

133-
when(metricsHandler.onResponse(anyRequest(), response.capture()))
134-
.thenAnswer(_.getArgument(1))
140+
(handler.onResponse _)
141+
.expects(*, capture(response))
142+
.onCall { (_: HttpRequest, resp: HttpResponse) => resp }
135143

144+
val expectedRequest = HttpRequest()
136145
sink.request(1)
137-
source.sendNext(HttpRequest())
146+
source.sendNext(expectedRequest)
138147
sink.expectNext()
139148

140149
source.sendComplete()
141150
sink.expectComplete()
142151

143-
val expected = Marshal(StatusCodes.NotFound -> "The requested resource could not be found.")
152+
val expectedResponse = Marshal(StatusCodes.NotFound -> "The requested resource could not be found.")
144153
.to[HttpResponse]
145154
.futureValue
146155
.addAttribute(PathLabeler.key, "unhandled")
147-
response.getValue shouldBe expected
156+
157+
request.value shouldBe expectedRequest
158+
response.value shouldBe expectedResponse
148159
}
149160

150161
it should "call the metrics handler on error requests" in new Fixture {
151-
val request: ArgumentCaptor[HttpRequest] = ArgumentCaptor.forClass(classOf[HttpRequest])
152-
val response: ArgumentCaptor[HttpResponse] = ArgumentCaptor.forClass(classOf[HttpResponse])
153-
when(metricsHandler.onRequest(request.capture()))
154-
.thenAnswer(_.getArgument(0))
162+
val request = CaptureOne[HttpRequest]()
163+
val response = CaptureOne[HttpResponse]()
164+
(handler.onRequest _)
165+
.expects(capture(request))
166+
.onCall { (req: HttpRequest) => req }
155167

156-
when(server.apply(anyRequestContext()))
157-
.thenAnswer(invocation => failWith(new Exception("BOOM!"))(invocation.getArgument[RequestContext](0)))
168+
server
169+
.expects(*)
170+
.onCall(failWith(new Exception("BOOM!")))
158171

159-
when(metricsHandler.onResponse(anyRequest(), response.capture()))
160-
.thenAnswer(_.getArgument(1))
172+
(handler.onResponse _)
173+
.expects(*, capture(response))
174+
.onCall { (_: HttpRequest, resp: HttpResponse) => resp }
161175

176+
val expectedRequest = HttpRequest()
162177
sink.request(1)
163-
source.sendNext(HttpRequest())
178+
source.sendNext(expectedRequest)
164179
sink.expectNext()
165180

166181
source.sendComplete()
167182
sink.expectComplete()
168183

169-
val expected = Marshal(StatusCodes.InternalServerError)
184+
val expectedResponse = Marshal(StatusCodes.InternalServerError)
170185
.to[HttpResponse]
171186
.futureValue
172187
.addAttribute(PathLabeler.key, "unhandled")
173-
response.getValue shouldBe expected
188+
189+
request.value shouldBe expectedRequest
190+
response.value shouldBe expectedResponse
174191
}
175192

176193
}

core/src/test/scala/fr/davit/pekko/http/metrics/core/MeterStageSpec.scala

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import org.apache.pekko.stream.ClosedShape
2222
import org.apache.pekko.stream.scaladsl.{GraphDSL, RunnableGraph}
2323
import org.apache.pekko.stream.testkit.scaladsl.{TestSink, TestSource}
2424
import org.apache.pekko.testkit.TestKit
25-
import org.mockito.Mockito.{mock, verify, when}
25+
import org.scalamock.scalatest.MockFactory
2626
import org.scalatest.concurrent.ScalaFutures
2727
import org.scalatest.flatspec.AnyFlatSpecLike
2828
import org.scalatest.matchers.should.Matchers
@@ -31,13 +31,24 @@ class MeterStageSpec
3131
extends TestKit(ActorSystem("MeterStageSpec"))
3232
with AnyFlatSpecLike
3333
with Matchers
34+
with MockFactory
3435
with ScalaFutures {
3536

3637
private val request = HttpRequest()
3738
private val response = HttpResponse()
39+
private val error = new Exception("BOOM!")
3840

3941
trait Fixture {
40-
val handler: HttpMetricsHandler = mock(classOf[HttpMetricsHandler])
42+
val handler = stub[HttpMetricsHandler]
43+
44+
(handler.onConnection _).when().returns((): Unit)
45+
(handler.onDisconnection _).when().returns((): Unit)
46+
(handler.onRequest _).when(request).returns(request)
47+
(handler.onResponse _).when(request, response).returns(response)
48+
(handler.onFailure _).when(request, error).returns(error)
49+
(handler.onFailure _)
50+
.when(request, MeterStage.PrematureCloseException)
51+
.returns(MeterStage.PrematureCloseException)
4152

4253
val (requestIn, requestOut, responseIn, responseOut) = RunnableGraph
4354
.fromGraph(
@@ -73,22 +84,21 @@ class MeterStageSpec
7384
responseIn.sendComplete()
7485
responseOut.expectComplete()
7586

76-
verify(handler).onConnection()
77-
verify(handler).onDisconnection()
87+
(handler.onConnection _).verify()
88+
(handler.onDisconnection _).verify()
7889
}
7990

8091
it should "call onRequest wen request is offered" in new Fixture {
81-
when(handler.onRequest(request)).thenReturn(request)
8292
requestIn.sendNext(request)
8393
requestOut.expectNext() shouldBe request
8494

85-
when(handler.onResponse(request, response)).thenReturn(response)
8695
responseIn.sendNext(response)
8796
responseOut.expectNext() shouldBe response
97+
98+
(handler.onRequest _).verify(request)
8899
}
89100

90101
it should "flush the stream before stopping" in new Fixture {
91-
when(handler.onRequest(request)).thenReturn(request)
92102
requestIn.sendNext(request)
93103
requestOut.expectNext() shouldBe request
94104

@@ -97,71 +107,69 @@ class MeterStageSpec
97107
requestOut.expectComplete()
98108

99109
// response should still be accepted
100-
when(handler.onResponse(request, response)).thenReturn(response)
101110
responseIn.sendNext(response)
102111
responseOut.expectNext() shouldBe response
112+
113+
(handler.onRequest _).verify(request)
114+
(handler.onResponse _).verify(request, response)
103115
}
104116

105117
it should "propagate error from request in" in new Fixture {
106-
when(handler.onRequest(request)).thenReturn(request)
107-
108118
requestIn.sendNext(request)
109119
requestOut.expectNext() shouldBe request
110120

111-
val error = new Exception("BOOM!")
112121
requestIn.sendError(error)
113122
requestOut.expectError(error)
123+
124+
(handler.onRequest _).verify(request)
114125
}
115126

116127
it should "propagate error from request out" in new Fixture {
117-
when(handler.onRequest(request)).thenReturn(request)
118-
119128
requestIn.sendNext(request)
120129
requestOut.expectNext() shouldBe request
121130

122-
val error = new Exception("BOOM!")
123131
requestOut.cancel(error)
124132
requestIn.expectCancellation()
133+
134+
(handler.onRequest _).verify(request)
125135
}
126136

127137
it should "terminate and fail pending" in new Fixture {
128-
when(handler.onRequest(request)).thenReturn(request)
129-
130138
requestIn.sendNext(request)
131139
requestIn.sendComplete()
132140
requestOut.expectNext() shouldBe request
133141
requestOut.expectComplete()
134142

135-
when(handler.onFailure(request, MeterStage.PrematureCloseException)).thenReturn(MeterStage.PrematureCloseException)
136143
responseIn.sendComplete()
137144
responseOut.expectComplete()
145+
146+
(handler.onRequest _).verify(request)
147+
(handler.onFailure _).verify(request, MeterStage.PrematureCloseException)
138148
}
139149

140150
it should "propagate error from response in and fail pending" in new Fixture {
141-
when(handler.onRequest(request)).thenReturn(request)
142-
143151
requestIn.sendNext(request)
144152
requestIn.sendComplete()
145153
requestOut.expectNext() shouldBe request
146154
requestOut.expectComplete()
147155

148-
val error = new Exception("BOOM!")
149-
when(handler.onFailure(request, error)).thenReturn(error)
150156
responseIn.sendError(error)
151157
responseOut.expectError(error)
158+
159+
(handler.onRequest _).verify(request)
160+
(handler.onFailure _).verify(request, error)
152161
}
153162

154163
it should "propagate error from response out and fail pending" in new Fixture {
155-
when(handler.onRequest(request)).thenReturn(request)
156-
157164
requestIn.sendNext(request)
158165
requestIn.sendComplete()
159166
requestOut.expectNext() shouldBe request
160167
requestOut.expectComplete()
161168

162-
val error = new Exception("BOOM!")
163-
when(handler.onFailure(request, error)).thenReturn(error)
164169
responseOut.cancel(error)
165170
responseIn.expectCancellation()
171+
172+
(handler.onRequest _).verify(request)
173+
(handler.onFailure _).verify(request, error)
166174
}
167175
}

project/Dependencies.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ object Dependencies {
88
val DropwizardV5 = "5.0.0"
99
val Enumeratum = "1.7.3"
1010
val Logback = "1.5.3"
11-
val Mockito = "5.9.0"
1211
val Pekko = "1.0.2"
1312
val PekkoHttp = "1.0.1"
1413
val Prometheus = "0.16.0"
1514
val ScalaCollectionCompat = "2.11.0"
1615
val ScalaLogging = "3.9.5"
16+
val ScalaMock = "6.0.0-M2"
1717
val ScalaTest = "3.2.18"
1818
}
1919

@@ -35,7 +35,6 @@ object Dependencies {
3535
val DropwizardJvm = "io.dropwizard.metrics" % "metrics-jvm" % Versions.Dropwizard % "test"
3636
val DropwizardV5Jvm = "io.dropwizard.metrics5" % "metrics-jvm" % Versions.DropwizardV5 % "test"
3737
val Logback = "ch.qos.logback" % "logback-classic" % Versions.Logback % "test"
38-
val Mockito = "org.mockito" % "mockito-core" % Versions.Mockito % "test"
3938
val PekkoHttpJson = "org.apache.pekko" %% "pekko-http-spray-json" % Versions.PekkoHttp % "test"
4039
val PekkoHttpTestkit = "org.apache.pekko" %% "pekko-http-testkit" % Versions.PekkoHttp % "test"
4140
val PekkoSlf4j = "org.apache.pekko" %% "pekko-slf4j" % Versions.Pekko % "test"
@@ -44,6 +43,7 @@ object Dependencies {
4443
val PrometheusHotspot = "io.prometheus" % "simpleclient_hotspot" % Versions.Prometheus % "test"
4544
val ScalaCollectionCompat =
4645
"org.scala-lang.modules" %% "scala-collection-compat" % Versions.ScalaCollectionCompat % "test"
46+
val ScalaMock = "org.scalamock" %% "scalamock" % Versions.ScalaMock % "test"
4747
val ScalaTest = "org.scalatest" %% "scalatest" % Versions.ScalaTest % "test"
4848
}
4949
}

0 commit comments

Comments
 (0)