[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [aspectj-users] AspectJ around singleton for testing
|
> So here's my question. I'd like to avoid the whole line being called. Is there a simple way to do an around
> advise that goes around both calls at once? Ie. Around an entire expression: OurHttpClient.getInstance().postTo(..)?
Not around both calls at once, no. I took your code and knocked this up:
public class C {
public static void main(String[] args) {
String s = OurHttpClient.getInstance().postTo("abc","def");
}
}
class OurHttpClient {
private static OurHttpClient instance;
private OurHttpClient() {
System.out.println("original private ctor running");
}
public static OurHttpClient getInstance() {
System.out.println("original getInstance running");
if (instance == null) { instance = new OurHttpClient(); }
return instance;
}
public String postTo(String url, String msg) {
System.out.println("original postTo() running");
return "foo";/* does post and returns response */
}
}
when run it produces:
original getInstance running
original private ctor running
original postTo() running
Then two options, the one you seem to want to write:
aspect A {
public OurHttpClient.new(String s) {super(); }
OurHttpClient around(): execution(* OurHttpClient.getInstance()) {
return new OurHttpClient("");
}
}
and when run, results in:
original postTo() running
Or the alternative with a subtype:
aspect A {
// Could override execution of getInstance() to return MyHttpClient
OurHttpClient around(): call(OurHttpClient.new(..)) {
return new MyHttpClient();
}
public OurHttpClient.new(String s) { super();}
}
The around advice on the ctor returns the subtype that we want to
create. Because our subtype needs a reachable ctor in OurHttpClient,
the aspect also adds one - it has to have a parameter to differentiate
from the one that is already there (bit ugly...)
class MyHttpClient extends OurHttpClient {
MyHttpClient() {
super(null);
}
public String postTo(String url, String msg) {
return "foo";
}
}
Then I can run it again:
original getInstance running
cheers,
Andy
On 15 March 2010 15:40, <William.J.McDonald@xxxxxxxxxxxxxx> wrote:
> I'm looking at doing some system testing and mocking out (simulating
> responses from) other systems. The problem is that many of the points of
> control to the system that I want to mock out are at library object calls
> that are implemented as singletons. For example, I'd like to mock out the
> postTo call, and also avoid the setup code done by the private constructor:
>
> response = OurHttpClient.getInstance().postTo(url, msg);
>
> Where OurHttpClient code is in a library jar file like this:
>
> public class OurHttpClient {
> private static OurHttpClient instance;
> private OurHttpClient() { /* do some setup things that I don't want
> to run during my system testing */ }
> public static OurHttpClient getInstance() { if (instance == null) {
> instance = new OurHttpClient(); } return instance; }
> public String postTo(String url, String msg) { /* does post and
> returns response */ }
> }
>
> Again, I want to put in a mock so that when the postTo is called, I can
> return my canned response, simulating the system's indirect input. I also
> don't want some of the things that the private constructor does in the class
> to happen. (This is a simple example, but I have other singletons that
> access JNDI for datasources and JMS queues and I want to run this outside
> the EJB container too).
>
> I first thought about putting an around advice for the getInstance()
> method. The problem is that the next thing to execute after that would be
> the postTo(..) method on an OurHttpClient object instance, and because of
> how the singleton is written, I can't return an instance of OurHttpClient
> without going through the setup code inside the constructor.
>
> Initially I opted for a non AOP solution, powerMockito. I planned on
> replacing the getInstance() call to OurHttpClient with one that returned
> MyHttpClientMock. But, as I described, the problem was that the next call
> needed an object of type OurHttpClient when it calls the postTo method. So
> I made MyHttpClientMock a subclass of OurHttpClient thinking that I'd have
> an instance with which to call the postTo method that I could override:
>
> public class MyHttpClientMock extends OurHttpClient {
> public static MyHttpClientMock getInstance() { return new
> MyHttpClientMock(); }
> public String postTo(String url, String msg) { /* returns simulated
> response */ }
> }
>
> The problem with this is that eclipse complains about not being able to call
> the OurHttpClient() constructor. Now what?
>
> Does aspectJ allow me to add another constructor to OurHttpClient, change
> the getInstance to point to it, so I can then mock out postTo() like I
> wanted to in the first place?
>
> public class OurHttpClient {
> private static OurHttpClient instance;
> /* woven in via aspectj: */
> private OurHttpClient(String dummy) { }
>
> private OurHttpClient() { /* do some setup things that I don't want
> to run during my system testing */ }
> public static OurHttpClient getInstance() {
> if (instance == null) {
> instance = new OurHttpClient(); // AOP CHANGES THIS
> TO new OurHttpClient("dummy");
> }
> return instance;
> }
> public String postTo(String url, String msg) { /* does post and
> returns response */ }
> }
>
> As it turned out, in some of the cases I'm coding, the class I wanted to
> mock out actually called 'new' on another class, and I was able to join my
> code at that point, but I just got lucky that the 'new' call was done in the
> constructor before any of the setup code I didn't want to run happened.
>
> When I consider using aspectj instead of powermockito to mock out the call,
> I still need to make sure the class's private constructor doesn't really get
> called. I want to do an around advise of the getInstance, but I think I'm
> going to run into the same problem of requiring the around advise to return
> an object of type OurHttpClient so that the call to .postTo() is correct. I
> don’t think I can give it just any object that implements postTo instead -
> it has to be one of type OurHttpClient, no?
>
> So here's my question. I'd like to avoid the whole line being called. Is
> there a simple way to do an around advise that goes around both calls at
> once? Ie. Around an entire expression:
> OurHttpClient.getInstance().postTo(..)?
>
> I'm trying to setup regression testing before refactoring, and wanted to be
> able to test without changing the SUT code.
>
> TIA,
>
> Bill McDonald
> William.J.McDonald@xxxxxxxxxxxxxx
> 480-456-8417 office
> CSTS (Consumer Credit Services and Technology Solutions)
>
> This message may contain confidential and/or privileged information. If you
> are not authorized to receive this message, you must not take any action on
> this message. If you have received this message in error, please advise the
> sender immediately by reply e-mail and delete this message. Thank you for
> your cooperation.
>
>
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>
>