Hi, David, Thanks for taking some time to look at this problem. I'm a little concerned about the approach, though - should Lift really behave significantly differently in test mode than it does in production mode? This seems like it would lend to the possibility of subtle bugs that don't show up until one is in production.
With respect to unit testing, Lift's singletons depend upon underlying thread-local variables (via ThreadGlobal) to maintain state. I'm just musing here, but do you think it might be possible to inject a layer of indirection between Lift's singletons and the underlying state mechanism so that the state maintenance layer could be mocked out for tests? This brings some other issues I've been wrangling with lately to mind. Please forgive me for rambling, but I think that the issue of testing is intimately tied to how Lift deals with state maintenance. State is sort of becoming a bugbear for me as my Lift app becomes more complex. I'm not sure whether I'm just doing things wrong or what, but I'm finding that using RequestVars and StatefulSnippets to maintain state makes it difficult to build composable editing components. As an example, I've got a StatefulSnippet that I use to build an object of type EventTrigger. There are a few possible subclasses of EventTrigger that can be produced through the workflow managed by the StatefulSnippet, and switching between the type options and such works well. The problem is that an EventTrigger may be associated with some number of Products, of which there are also a number of subclasses. So, I also have a similar StatefulSnippet that manages the flow of creating Products. But how do I pass the state of a newly created (or selected existing) EventTrigger from one StatefulSnippet to the next? As far as I can tell, there is no way to hand off control between StatefulSnippet instances - instead I must populate a RequestVar and use a redirect in the transition. Both sides of this state transaction have expectations of the state of the intermediate RequestVar, but there is no way to enforce that it be populated before the second snippet attempts to use it. This feels very Model 1 to me. It's the same case wherever I use RequestVar - some component (say a link) sets a value, then some other component reads it, and while the ReqestVar provides type safety for the value type, there is no associated type safety available for the call, as both links and redirects simply use strings to define behavior. This all seems to fall out of the fact that the processing of a template at a Loc results in reflective invocation of snippet functions. The template itself, which is outside the type system, defines the behavior at a Loc. As such, every snippet must be written to operate correctly in the absence of any piece of the state it expects. At least in my app, this ends up as an obnoxiously large amount of boilerplate. I think that I must be doing something wrong, because the feel of my app is that it is held together by snot and string, threaded through RequestVars that I hope will be populated with the correct values at the correct times and redirects that I hope are pointing to the right locations. At the same time, I can't figure out how else Lift will permit me to handle my state. With each new feature I add, I become a little more dismayed. Please, how can I handle these problems better? Thanks, Kris On Fri, Jul 3, 2009 at 10:43 AM, David Pollak<[email protected]> wrote: > Jeppe, > > Once I check in some code (in about 20 minutes), if you run Lift in Test > mode (-Drun.mode=test), forms, etc. will have stable names which makes > testing easier. > > Thanks, > > David > > On Thu, Jul 2, 2009 at 1:13 PM, Jeppe Nejsum Madsen <[email protected]> > wrote: >> >> Hi, >> >> Having taken the first baby steps and gotten a Lift app running, it's >> time to bring back some of the old engineering practices to make sure >> things keep running when new features are added at a rapid pace :-) >> >> I'm interested in how people are testing their Lift apps, both at the >> unit test level (ie. specs/scalatest with no container) and at the >> integration test level (running in servlet container). Also, how are you >> doing TDD with Lift (if at all). >> >> Specifically, I've run into the following issues: >> >> 1) Testing model classes. Many require access to S (ie to read >> resources) or other static Lift constructs. How can you mock these? >> >> 2) Testing snippets. Same issue with S, but more related to the actual >> request, eg. S.param >> >> For in-container testing it seems the practice of generating unique >> names for form fields, makes it difficult to use tools like Selenium to >> do browser based testing? How do you handle this? >> >> Any input is appreciated >> >> /Jeppe >> >> > > > > -- > Lift, the simply functional web framework http://liftweb.net > Beginning Scala http://www.apress.com/book/view/1430219890 > Follow me: http://twitter.com/dpp > Git some: http://github.com/dpp > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Lift" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---
