2013/7/12 Miguel Almeida <[email protected]>: > I'd like to discuss with you an idea that came up a while ago while > trying to fulfil this need: > > As a developer > I want to unit test annotations in my actions without having to run the > method's body > So that I can TDD more effectively and have quicker unit tests. > > Namely, imagine an action: > > @SecuredRoles("admin") > public String adminStuff(){ > ... > } > > It would be interesting to have a way to test the @SecuredRoles without > having to run the method's body. > > Upon discussion within the TDD group, a nice solution was suggested (in > italic. Skip below for my comments regarding Struts) : > > So I would test and implement each aspect in isolation of the other - > the authorization would be implemented as a decorator (a-la GoF > decorator pattern) adding authorization to the underlaying (decorated) > MVC app. BTW I got to this technique by TDDing the separate aspects > (this is a good example of where the tests drive the design). > > The technique to getting there is quite simple: > 1. Extract an interface from your main class with all the public methods > > 2. Implement a decorator which adds authorization rules to a decorated > underlaying object. The decorator can implement the authorization rules > using your annotations (see this is where the academic meets the > practical - you'll in fact be reusing the already existing interceptor > but adapting it to a test-driven architecture) > > 3. in your tests, test the decorator providing a mock underlaying > decorated object, asserting in each test that given a request with a > user that has certain roles the underlaying method should or should not > be called. > > The code might end up like this (semi-pseudo code but you get the idea) > > > Tests: > > test_admin_can_call_method_a() > { > // setup a fake request with admin role: > httpRequest = buildRequestWithRole("admin"); > > // setup a mock app decorated with an authorzation decorator: > MockApp app = new MockApp(); > AuthorizationDecorator authorizer = new AuthorizationDecorator(app); > > // act - try calling method A in the decorator: > authorizer.MethodA(httpRequest); > > // assert - underlaying method a should have been called: > Assert(app.MethodA.WasCalled==true); > } > > test_regularUser_cannot_call_method_a() > { > // setup a fake request with regular user role: > httpRequest = buildRequestWithRole("regular user"); > > // setup a mock app decorated with an authorzation decorator: > MockApp app = new MockApp(); > AuthorizationDecorator authorizer = new AuthorizationDecorator(app); > > // act - try calling method A in the decorator: > authorizer.MethodA(httpRequest); > > // assert - underlaying method a should not have been called: > Assert(app.MethodA.WasCalled==false); > } > > > > In the SUT: > > interface IApp > { > void MethodA() > void MethodB() > ... > } > > // this is the real app implementing methodA, methodB etc > class RealApp : IApp > { > void MethodA() > void MethodB() > ... > } > > // this is responsible for authorization > class AuthorizingDecorator : IApp > { > private IApp _decorated; > public AuthorizationDecorator(IApp decorated) > { > _decorated = decorated; > } > > // each method is implemented using annotations > // and calling the underlaying decorated object > @SecuredRoles("admin, manager") > public void MethodA() > { > _decorated.MethodA(); > } > > > > @SecuredRoles("regular user") > public void MethodB() > { > _decorated.MethodB(); > } > } > > Then in your final MVC application you'd wire up the decorator with the > RealApp object: > > IApp app = new AuthorizingDecorator(new RealApp()); > > > > This design is incompatible with Struts2 - if you decorate > DecoratedAction with OriginalAction, all Struts-related things (e.g. > ParamsInterceptor populating Action's fields from request, and I assume > every other interceptor's behaviour as well) will no work on > DecoratedAction, because it doesn't extend OriginalAction but rather > delegates to OriginalAction. E.g, a "someRequestParam" would be > populated OriginalAction if it was in the request, but it won't populate > originalAction.someRequestParam in DecoratedAction. > > It would be very interesting to support the Decorator Pattern in Struts > actions. What are your thoughts on it?
Is it similar to ModelDriven? The problem I see is how to distinguish when to call decorator and when decorated object. Regards -- Ćukasz + 48 606 323 122 http://www.lenart.org.pl/ --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
