I am writing a utility program using a Swing GUI. I am trying to use Martin Fowler's Presentation Model to facilitate testing. My application will automatically store several user preferences using java.util.prefs.Preferences
(i.e.: main window position and size). I spent several hours over the weekend trying to create a Clojure mock of the Preferences
API (using EasyMock) so that I could test my presenter code, but could not get it working. Clojure GUI programming using non-OO style is hard for a long-time OO programmer. I feel that if I can discover/develop patterns for these things (mocking, "interfaces" for visual "classes", etc.), I can continue to use the same patterns throughout the rest of the application.
I have also been developing the same application in Scala to compare the programming patterns and have found it to be much more intuitive, even though I am trying to use Scala in a fairly strict functional style (excluding, of course, calls to Java classes like the Swing API -- which will have the same mutability issues in the Clojure version, but of course, will also be single-threaded).
In my Scala code, I create a class called MainFrame
that extends JFrame
and implements the trait MainView
. MainView
exposes all of the JFrame
calls as abstract methods that I can implement in a mock object:
trait LabelMethods {
def setText(text: String)
//...
}
trait PreferencesMethods {
def getInt(key: String, default: Int): Int
def putInt(key: String, value: Int)
//...
}
trait MainView {
val someLabel: LabelMethods
def addComponentListener(listener: ComponentListener)
def getLocation: Point
def setVisible(visible: Boolean)
// ...
}
class MainFrame extends JFrame with MainView {
val someLabel = new JLabel with LabelMethods
// ...
}
class MainPresenter(mainView: MainView) {
//...
mainView.addComponentListener(new ComponentAdaptor {
def componentMoved(ev: ComponentEvent) {
val location = mainView.getLocation
PreferencesRepository.putInt("MainWindowPositionX", location.x)
PreferencesRepository.putInt("MainWindowPositionY", location.y)
}
mainView.someLabel.setText("Hello")
mainView.setVisible(true)
}
class Main {
def main(args: Array[String]) {
val mainView = new MainFrame
new MainPresenter(mainView)
}
}
class TestMainPresenter {
@Test def testWindowPosition {
val mockPreferences = EasyMock.mock(classOf[PreferencesMethods])
//... setup preferences expectation, etc.
PreferencesRepository.setInstance(mockPreferences)
val mockView = EasyMock.createMock(classOf[MainView])
//... setup view expectations, etc.
val presenter = new MainPresenter(mockView)
//...
}
}
I am using a pseudo-singleton (setInstance
included so that a mock can replace the "real" version) for the Preferences, so the details are not shown. I know about the cake pattern, but found mine to be a little easier to use in this case.
I have struggled with doing the similar code in Clojure. Are there any good examples of open-source projects that do this kind of thing? I have read several books on Clojure (Programming Clojure, The Joy of Clojure, Practical Clojure), but have not seen these issues dealt with. I have also studied Rich Hickey's ants.clj
, but his use of Swing in that example is pretty basic.
Check these two options that are quite popular in the clojure world:
Edit: Fresh info: https://tonsky.me/blog/skija/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With