Mockito testing events - mockito

I have a class which generates events e.g.
public class EventSource{
public addEventListener(EventListener listener).....
public raiseEvent(){
Event e=....
listener.handle(e);
}
}
I'm using Mockito to mock an EventListener and want to do an equality on the event object (e.g. event.getTime()..event.getMessage() etc). The event object doesnt have an equals method so I cant easily create another object and do an assert.
Whats the normal way of doing this with Mockito?

It looks like you want to use an argument captor.
For example:
ArgumentCaptor<Event> argument = ArgumentCaptor.forClass(Event.class);
verify(mockedListener).handle(argument.capture());
assertEquals("ExpectedMessage", argument.getValue().getMessage());

Related

What type of data should be passed to domain events?

I've been struggling with this for a few days now, and I'm still not clear on the correct approach. I've seen many examples online, but each one does it differently. The options I see are:
Pass only primitive values
Pass the complete model
Pass new instances of value objects that refer to changes in the domain/model
Create a specific DTO/object for each event with the data.
This is what I am currently doing, but it doesn't convince me. The example is in PHP, but I think it's perfectly understandable.
MyModel.php
class MyModel {
//...
private MediaId $id;
private Thumbnails $thumbnails;
private File $file;
//...
public function delete(): void
{
$this->record(
new MediaDeleted(
$this->id->asString(),
[
'name' => $this->file->name(),
'thumbnails' => $this->thumbnails->toArray(),
]
)
);
}
}
MediaDeleted.php
final class MediaDeleted extends AbstractDomainEvent
{
public function name(): string
{
return $this->payload()['name'];
}
/**
* #return array<ThumbnailArray>
*/
public function thumbnails(): array
{
return $this->payload()['thumbnails'];
}
}
As you can see, I am passing the ID as a string, the filename as a string, and an array of the Thumbnail value object's properties to the MediaDeleted event.
How do you see it? What type of data is preferable to pass to domain events?
Updated
The answer of #pgorecki has convinced me, so I will put an example to confirm if this way is correct, in order not to change too much.
It would now look like this.
public function delete(): void
{
$this->record(
new MediaDeleted(
$this->id,
new MediaDeletedEventPayload($this->file->copy(), $this->thumbnail->copy())
)
);
}
I'll explain a bit:
The ID of the aggregate is still outside the DTO, because MediaDeleted extends an abstract class that needs the ID parameter, so now the only thing I'm changing is the $payload array for the MediaDeletedEventPayload DTO, to this DTO I'm passing a copy of the value objects related to the change in the domain, in this way I'm passing objects in a reliable way and not having strange behaviours if I pass the same instance.
What do you think about it?
A domain event is simply a data-holding structure or class (DTO), with all the information related to what just happened in the domain, and no logic. So I'd say Create a specific DTO/object for each event with the data. is the best choice. Why don't you start with the less is more approach? - think about the consumers of the event, and what data might they need.
Also, being able to serialize and deserialize the event objects is a good practice, since you could want to send them via a message broker (although this relates more to integration events than domain events).

How to decorate the final class DocumentGenerator

I am having problems to decorate the final class "DocumentGenerator" (in vendor/shopware/core/Checkout/Document/Service/DocumentGenerator.php) and overwrite the "generate" function inside of it.
I tried to decorate it the usual way, but an error is thrown because the "DocumentController" class excepts the original class and not my decorated one?
Argument 2 passed to Shopware\Core\Checkout\Document\DocumentGeneratorController::__construct() must be an instance of Shopware\Core\Checkout\Document\Service\DocumentGenerator
Its also not possible to extend from the class in my decorated class, because the "DocumentGenerator" is a final class.
My goal is to execute additional code, after an order document is generated. Previously I successfully used to decorate the "DocumentService" Class, but its marked as deprecated and shouldnt be used anymore. Also the "DocumentGenerator" class is used for the new "bulkedit" function for documents as of Version 6.4.14.0
I'm grateful for every tip.
As #j_elfering already wrote it's by design that you should not extend that class and therefore also shouldn't decorate it.
To offer a potential alternative:
Depending on what you want to do after a document has been generated it might be enough to add a subscriber to listen to document.written, check if it was a new document created and then work with the data from the payload for fetching/persisting data depending on that.
public static function getSubscribedEvents()
{
return [
'document.written' => 'onDocumentWritten',
];
}
public function onDocumentWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if ($result->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
// skip if the it's not a new document created
continue;
}
$payload = $result->getPayload();
// do something with the payload
}
}
Probably not what you want to hear but: The service is final in purpose as it is not intended to be decorated.
So the simple answer is you can't. Depending on your use case there may be other ways that don't rely on decoration.

Mocking a public method that has a private method call inside using Mockito (not Powermockito)

I am testing for methodA() in the class :
class Test{
public String methodA(String str){
...
methodB("s1","s2");
...
}
private String methodB(String s1, String s2){
...
}
}
What I have tried in my test class:
Method methodBReflect = Test.class.getDeclaredMethod("methodB", Test.class,String.class, String.class);
methodBReflect.setAccessible(true);
Test testForSpy=new Test();
Test spyTest=spy(testForSpy);
doReturn("return string").when(spyTest..)... // <-- What should be done here?
//methodBReflect.invoke(spyTest, "args1","args2");
P.S: I don't need a solution using powermock as I have some organizational constraints using it.
You shouldn't be testing that method A calls method B. You should test that method A does what method A is supposed to do - that is, it gives the correct output for whatever input you give it. Your test shouldn't care whether method A works by calling method B, or by doing all its processing inline.
Therefore, there's no need to mock or stub anything. Your tests will consist of a bunch of calls to method A, along with verification that the output is what you expect.
You only need to use Mockito (or some other mocking framework) when you're testing a class that interacts with another class entirely; not when the class under test interacts with itself.

Intercepting ClassCastException's in Groovy?

I have a lot of code using and expecting java.util.Date which I would like to migrate to org.joda.time.LocalDate. The problem is that most of the code is dynamically typed.
So I wonder if there is any groovy way to intercept the ClassCastException, do the conversion at runtime (instead of letting the exception bubble up) and log the operation (so I could fix the code).
Example:
import org.joda.time.LocalDate
def someMethod(date) {
println date.year()
}
// this call is ok
someMethod(new LocalDate())
// this call raises an exception
someMethod(new Date())
I don't want to modify the code above, like surrounding the second call with a try-catch and recalling with the right type. I wanted a way to do this globally.
Idea 1:
You can benefit from Groovy multimethods: you write a method overload for the JodaTime's and let the java.util.Date method be chosen when it is a dynamic method parameter:
def someMethod(date) {
println date.year()
}
My advice is to write in this class a overload of these methods doing the conversion:
def someMethod(LocalDate date) {
someMethod date.convertToJavaDate()
}
If you don't have access to that code, you can use metaprogramming.
Idea 2:
If you have a huge library, my guess is that you are better mixing JodaTime class. You will get a power benefit from duck typing. You will need to know which members from java.util.Date are called and reroute them to Joda's own methods:
class LocalDateMixin {
def year() { this[Calendar.YEAR] }
}
LocalDate.metaClass.mixin LocalDateMixin
You can also apply the metaprogramming using extension methods.

How can I intercept execution of all the methods in a Java application using Groovy?

Is it possible to intercept all the methods called in a application? I'd like to do something with them, and then let them execute. I tried to override this behaviour in Object.metaClass.invokeMethod, but it doesn't seem to work.
Is this doable?
Have you looked at Groovy AOP? There's very little documentation, but it allows you to define pointcuts and advice in a conceptually similar way as for AspectJ. Have a look at the unit tests for some more examples
The example below will match all calls to all woven types and apply the advice before proceeding:
// aspect MyAspect
class MyAspect {
static aspect = {
//match all calls to all calls to all types in all packages
def pc = pcall("*.*.*")
//apply around advice to the matched calls
around(pc) { ctx ->
println ctx.args[0]
println ctx.args.length
return proceed(ctx.args)
}
}
}
// class T
class T {
def test() {
println "hello"
}
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class
First of all, overriding Object.metaClass.invokeMethod doesn't work because when Groovy tries to resolve a method call for a type X, it checks the metaClass of X, but not the metaClass of its parent class(es). For example, the following code will print "method intValue intercepted"
Integer.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Integer.metaClass = null
But this code will not:
Object.metaClass.invokeMethod = {def name, def args ->
System.out.println("method $name intercepted")
}
6.intValue()
// Reset the metaClass
Object.metaClass = null
Your question was "Is it possible to intercept all the methods called in a application?", but could you be a bit more precise about whether you want to:
Intercept calls to Groovy methods, Java methods, or both
Intercept calls to only your Groovy/Java methods or also intercept calls to Groovy/Java library classes
For example, if you only want to intercept calls to your Groovy classes, you could change your classes to implement GroovyInterceptable. This ensures that invokeMethod() is invoked for every method called on those classes. If the nature of the interception (i.e. the stuff you want to do before/after invoking the called method) is the same for all classes, you could define invokeMethod() in a separate class and use #Mixin to apply it to all your classes.
Alternatively, if you also want to intercept calls to Java classes, you should check out the DelegatingMetaClass.

Resources