ScalaMock中`(myClass.myMethod _).expects()`语法含义及原理问询
(myClass.myMethod _).expects() Syntax Hey there! Let's break down this ScalaMock syntax piece by piece—this stuff can feel confusing when you're new to Scala and mocking frameworks, but once you unpack each part, it makes perfect sense.
Let's Split the Expression First
The line (myClass.myMethod _).expects() is actually two key parts working together:
(myClass.myMethod _): Converting a method into a referenceable function.expects(): ScalaMock's API to set up call expectations
1. What's myClass.myMethod _ doing?
First, myClass is the mocked instance you've created (e.g., from mock[MyClass]), and myMethod is the method you want to define expectations for.
But here's the thing: In Scala, methods are not functions by default. A method is a member of a class/instance, while a function is a standalone object that can be passed around or referenced directly.
The underscore _ here triggers Scala's method-to-function conversion. It tells the compiler: "Don't call myMethod right now—instead, create a function value that wraps this method, so we can pass it to ScalaMock."
2. Why the parentheses around myClass.myMethod _?
Scala has strict operator precedence rules. If we wrote myClass.myMethod _.expects() without parentheses, the compiler would misinterpret it as trying to pass _.expects() (a partial function) as an argument to myMethod—which is not what we want at all.
The parentheses force the compiler to first resolve myClass.myMethod _ (convert the method to a function) before calling the expects() method on that function.
3. What does .expects() do?
Once we have a function reference to myMethod, expects() is ScalaMock's way of letting you define rules for how that method should be called during testing. For example:
(myClass.myMethod _).expects(42): ExpectmyMethodto be called with the argument42(myClass.myMethod _).expects(*).twice(): ExpectmyMethodto be called any number of times with any argument, exactly twice(myClass.myMethod _).expects(where(_ > 10)).returning("valid"): ExpectmyMethodto be called with a value greater than 10, and return "valid" when it does
Under the hood, the function we created with _ is actually a special ScalaMock type (like MockFunction1 for a single-argument method) that includes the expects() method. When you call expects(), ScalaMock records this expectation and checks it against actual method calls during test execution.
Compiler Breakdown Step-by-Step
Let's walk through how the compiler processes this line:
- It sees
myClass.myMethod _and recognizes it needs to convert the method to a function. It creates a function instance with the same parameter and return types asmyMethod. - The parentheses ensure this conversion happens before any other operations.
- The compiler then calls
expects()on the resulting function instance. - ScalaMock registers this expectation, so when your test runs, it verifies that
myMethodis called according to the rules you set.
Example in Context
Here's a quick concrete example to tie it all together:
// Define a trait we want to mock trait Calculator { def add(a: Int, b: Int): Int } // Create a mock instance val mockCalc = mock[Calculator] // Set up an expectation: add(2,3) should be called once, return 5 (mockCalc.add _).expects(2, 3).returning(5).once() // Run code that uses the mock val result = mockCalc.add(2, 3) // Verify the result matches our expectation assert(result == 5)
内容的提问来源于stack exchange,提问作者Roy Taylor

