Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on Mocking methods with arguments

Post

Mocking methods with arguments

+1
−3

Let's say I have this class I want to mock

class A {
    public void add(T arg) {
        B b = A.getB();
        U val = somefunc(arg);
        V ret = b.add(val);
    }
}

I have a spy on A and a mock on B, but when A::foo calls B::bar, I want it to be mocked. But I want some stuff to be done inside it. Something like this:

class BMock {
    List<U> ulist = new ArrayList<>();

    R add(U u) {
        if(ulist.contains(u)) throw exception;
    }

    return new R(x);
}

But I'm having a bit of a problem how to do this. I'm looking for something on this form:

A a = spy(A.class);
B b = mock(B.class);
a.b = b;
BMock bm = new BMock();
doAnswer(bm.add(arg)).when(b).add(any());
                 ^                  |
                 |                  |
                  ------------------

What I want to do is to send the any argument over to bm.add

In the real code, B::add will contact a remote server to add an item. If it gets called twice with the same item, the server will return an error. A::add will analyze this return code and act accordingly. And this is what I'm trying to simulate. How should I do it?

EDIT

I got some suggestions in comment section. But I might add that I cannot change B because it's an external library, and the class B both misses default constructor and is final.

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

1 comment thread

I'm trying to test your code, but I think there are some details missing. I understood that `A::add` ... (7 comments)
I'm trying to test your code, but I think there are some details missing. I understood that `A::add` ...
hkotsubo‭ wrote almost 3 years ago

I'm trying to test your code, but I think there are some details missing. I understood that A::add calls B::add (as shown in the code), which in turn will call BMock::add (B code wasn't provided, so I'm guessing). Which one do you want to test?

"If it gets called twice with the same item" - In this case, "it" refers to A::add, B::add or BMock::add? How are you testing those calls? I see that A::add calls B::add just once, so I guess that A::add is being called multiple times - but how are those calls made?

klutt‭ wrote almost 3 years ago

In the real code, A::add calls B::add. I want to intercept this and make A::add call BMock::add instead.

And yes, A::add is being called multiple times. Well, actually it's kind of that I call A::import, which in turn will call A::add multiple times. So there is a bit of nesting here.

hkotsubo‭ wrote almost 3 years ago

In that case, you could do BMock extends B and then set a.b = new BMock()

klutt‭ wrote almost 3 years ago

When I saw what you wrote I thought "Omg, that's so obvious", but unfortunately, B does not have a default constructor :(

(And no, it cannot be added)

hkotsubo‭ wrote almost 3 years ago · edited almost 3 years ago

Well, inside BMock's constructor, just add super(whateverArgsBConstructorExpects) and that's it :-)

Or maybe you could use PowerMockito: see the "Replacing" section in this link

klutt‭ wrote almost 3 years ago

I really appreciate the help, but now I realized that B is a final class :D

I'll have a look. Thanks.

hkotsubo‭ wrote almost 3 years ago · edited almost 3 years ago

Let's see if I understood: B::add is called multiple times, and you want to check if all calls receives a different argument? Let's say, if it calls b.add(1) and b.add(2), the test passes, but if it calls b.add(1) twice, it fails.

Is BMock required for that? Or only checking for a repeated call (using whatever other mechanism, not necessarily BMock) solves your problem?