Mocking Scala traits containing abstract val members
I am writing a Swing application following Martin Fowler's Presentation Model pattern.
I create traits that contain abstract declarations of methods already implemented by Swing components:
trait LabelMethods {
def setText(text: String)
//...
}
trait MainView {
val someLabel: LabelMethods
def setVisible(visible: Boolean)
// ...
}
class MainFrame extends JFrame with MainView {
val someLabel 开发者_StackOverflow中文版= new JLabel with LabelMethods
// ...
}
class MainPresenter(mainView: MainView) {
//...
mainView.someLabel.setText("Hello")
mainView.setVisible(true)
}
How can I mock the someLabel
member of the MainView
trait using one of open-source mocking frameworks (EasyMock, Mockito, JMockit, etc.) for unit testing? Is there another mocking framework, perhaps specific to Scala that can do this?
Hah! Figured it out on the commute home :-).
Scala allows a val
in a concrete class to override a def
in a trait.
My traits become:
trait LabelMethods {
def setText(text: String)
//...
}
trait MainView {
def someLabel: LabelMethods // Note that this member becomes
// a def in this trait...
def setVisible(visible: Boolean)
// ...
}
My MainFrame
class does not need to change:
class MainFrame extends JFrame with MainView {
val someLabel = new JLabel with LabelMethods // ...But does not change
// in the class
// ...
}
My test case code looks like this:
class TestMainPresenter {
@Test def testPresenter {
val mockLabel = EasyMock.createMock(classOf[LabelMethods])
val mockView = EasyMock.createMock(classOf[MainView])
EasyMock.expect(mockView.someLabel).andReturn(mockLabel)
//... rest of expectations for mockLabel and mockView
val presenter = new MainPresenter(mockView)
//...
}
}
Note that I have not actually tested this, but it should work :-).
Actually, you don't need something to be a def
just to be able to mock it. According to Scala's Uniform Access Principle, the def
and val
are virtually the same from the outside. That is, for a val x
a getter method named x()
is generated, and a setter named x_=(newX)
is generated.
Thus the following works:
@Test
def testUap() {
abstract class A {
val x: Int
}
val mock = Mockito mock classOf[A]
Mockito when (mock.x) thenReturn 5
Assert.assertEquals(5, mock.x)
}
精彩评论