diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/FixedQuantity.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FixedQuantity.java similarity index 86% rename from deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/FixedQuantity.java rename to deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FixedQuantity.java index a339078b..f58bf84e 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/FixedQuantity.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FixedQuantity.java @@ -3,9 +3,7 @@ * This program is made available under the terms of the MIT License. */ -package de.ppi.deepsampler.core.internal; - -import de.ppi.deepsampler.core.api.Quantity; +package de.ppi.deepsampler.core.api; public class FixedQuantity implements Quantity { diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FunctionalSampleBuilder.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FunctionalSampleBuilder.java new file mode 100644 index 00000000..4f87ba67 --- /dev/null +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/FunctionalSampleBuilder.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.core.api; + +import de.ppi.deepsampler.core.model.Answer; +import de.ppi.deepsampler.core.model.SampleDefinition; + +/** + *

+ * Provides a fluent API for creating a {@link SampleDefinition} for methods that return a value (i.e. functions). + *

+ * + *

+ * With the FunctionalSampleBuilder you are able to define: + *

+ *

+ * The return value will be used (and evaluated) when the stubbed method will be invoked. + *

+ * + * @param type of the class you want stub + */ +public class FunctionalSampleBuilder extends VoidSampleBuilder { + + /** + * Create a {@link FunctionalSampleBuilder} with a sampler of the class you want to build a sample for, and the sampleDefinition + * you want to extend. + * + * @param sampler the sampler {@link Sampler} + * @param sampleDefinition {@link SampleDefinition} + */ + @SuppressWarnings("unused") + public FunctionalSampleBuilder(final T sampler, final SampleDefinition sampleDefinition) { + super(sampleDefinition); + } + + /** + * Defines the value, that will be returned when the stubbed method is invoked. This value is called the "Sample". + * + * @param sampleReturnValue the return value that should be returned by the stubbed method. + */ + public void is(final T sampleReturnValue) { + getSampleDefinition().setAnswer(stubInvocation -> sampleReturnValue); + } + + /** + * In most cases it will be sufficient to define a fixed Sample as a return value for a stubbed method, but sometimes it + * is necessary to execute some logic that would compute the return value or that would even change some additional state. + * This can be done by using an Answer like so: + * + * + * Sample.of(sampler.echo(anyString())).answer(invocation -> invocation.getParameters().get(0)); + * + *

+ * In essence using Answers gives free control on what a stubbed method should do. + * + * @param answer supplier you want to get evaluated when the stubbed method got invoked + */ + @SuppressWarnings("unchecked") + public void answers(final Answer answer) { + getSampleDefinition().setAnswer((Answer) answer); + } + +} diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSample.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSample.java new file mode 100644 index 00000000..9d321432 --- /dev/null +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSample.java @@ -0,0 +1,99 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.core.api; + +import de.ppi.deepsampler.core.error.NotASamplerException; +import de.ppi.deepsampler.core.internal.ProxyFactory; +import de.ppi.deepsampler.core.model.SampleDefinition; +import de.ppi.deepsampler.core.model.SampleRepository; + +import java.util.Objects; + +/** + * This is the starting point for the definition of Samples in test classes. + * + * A "Sample" is an exemplary return value or an exemplary behavior of a method that fulfills a prerequisite of a particular test case. When the tested methods are not able + * to reproduce the Sample by their own means (i.e. due to changes in the underlying database, or passing of time, etc.), the methods can be coerced to reproduce the Sample using + * this API. + * + * A method is called "sampled" if the method is coerced to return a Sample. + * + * Objects which contain sampled methods, are called "Sampler". + * + * DeepSampler defines Samples on classes rather then on objects. This enables DeepSampler to change the behavior of all instances of these classes without the need to instantiate + * the Sampler manually and to distribute the Sampler into the objects that will be tested. The distribution is done by a Dependency Injection Framework like Spring or Guice. + * + * Methods of the class {@link Object} are ignored. Otherwise strange effects might appear, e.g. if Object::finalize is + * called by the garbage collector. + * + * @author Jan Schankin, Rico Schrage + */ +public class PersistentSample { + + private PersistentSample() { + // This class is meant to be used as a frontend for a static fluent API and should never be instantiated. + } + + + /** + * Defines a sampled method by calling the method inside of the parameter. The returned {@link FunctionalSampleBuilder} will then offer possibilities to define the Sample, + * or in other words, it offers possibilities to override the default behavior or the return value of a method. + * + * @param sampledMethodCall The method call that will be sampled. + * @param The type of the return value and therefore the type of the Sample. + * @return A {@link FunctionalSampleBuilder} which can be used to define the concrete Sample. Do not keep references to this object, it is intended to be used as a + * fluent API only. + */ + public static PersistentSampleBuilder of(final T sampledMethodCall) { + SampleDefinition currentSampleDefinition = SampleRepository.getInstance().getCurrentSampleDefinition(); + SampleDefinition lastSampleDefinition = SampleRepository.getInstance().getLastSampleDefinition(); + + if (currentSampleDefinition == lastSampleDefinition) { + throw new NotASamplerException("sampledMethodCall is not a Sampler. Did you prepare the Sampler using Sampler.prepare() or @PrepareSampler?"); + } + + currentSampleDefinition.setMarkedForPersistence(true); + + SampleRepository.getInstance().setLastSampleDefinition(currentSampleDefinition); + return new PersistentSampleBuilder<>(sampledMethodCall, currentSampleDefinition); + } + + /** + * Along with the subsequent method call it defines a Sample for which the framework should start to track + * how often this Sample is used in the component. This is necessary to be able to verify the invocation + * of a specific method. + * + * @param sampler the sampler for which you want to activate a method call + * @param the type of the target Class/sampler + * @return the sampler itself + */ + public static T forVerification(final T sampler) { + Objects.requireNonNull(sampler); + + if (!ProxyFactory.isProxyClass(sampler.getClass())) { + throw new NotASamplerException(sampler.getClass()); + } + + SampleRepository.getInstance().setMarkNextVoidSamplerForPersistence(true); + + return sampler; + } + + + + /** + * This method will set the sampleId of the last defined sampleDefinition. Mostly you + * want to set the sampleId with the Method {@link PersistentSampleBuilder#hasId(String)}. But in case of + * void-returning methods, it is not possible to create a {@link FunctionalSampleBuilder}. As a consequence + * you will need to set the id with this method. + * + * @param id the id you want to set. + */ + public static void setIdToLastMethodCall(final String id) { + SampleRepository.getInstance().getCurrentSampleDefinition().setSampleId(id); + } + +} diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSampleBuilder.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSampleBuilder.java new file mode 100644 index 00000000..05ad3080 --- /dev/null +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/PersistentSampleBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.core.api; + +import de.ppi.deepsampler.core.model.SampleDefinition; + +/** + *

+ * Provides a fluent API for creating a {@link SampleDefinition} for persistent Samples that are loaded from a file or any other DataSource. + * The persistence (i.e. recording and loading samples) is managed by PersistentSampleManager. + *

+ * + *

+ * With the sampleBuilder you are able to define a sampleId, that is used to identify a Sample in the persistence. By default + * DeepSampler creates a sampleId from the signature of the stubbed method. If this signature is changed, maybe because of a future + * refactoring, the sample cannot be loaded from the persistence anymore. Defining manual sampleIds can be used to avoid this situation. + * + *

+ * + * @param type of the class you want stub + */ +public class PersistentSampleBuilder extends SampleBuilder { + + /** + * Create a {@link PersistentSampleBuilder} with a sampler of the class you want to build a sample for, and the sampleDefinition + * you want to extend. + * + * @param sampler the sampler {@link Sampler} + * @param sampleDefinition {@link SampleDefinition} + */ + @SuppressWarnings("unused") + public PersistentSampleBuilder(final T sampler, final SampleDefinition sampleDefinition) { + super(sampleDefinition); + } + + /** + * Set an id for the current SampleDefinition. The Id is used to find a Sample for a stubbed method. By default + * sampleIds are generated from the signature of the sampled method. Therefore a change of the signature would mean, that + * DeepSample isn't able anymore to find the Sample for the method. To prevent this situation, manual sampleIds can be used. + * + * @param sampleId the sampleId you want to set + * @return this + */ + public PersistentSampleBuilder hasId(final String sampleId) { + getSampleDefinition().setSampleId(sampleId); + return this; + } + + +} diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/Sample.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/Sample.java index 661b47f8..7d765083 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/Sample.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/Sample.java @@ -12,8 +12,6 @@ import de.ppi.deepsampler.core.model.SampleDefinition; import de.ppi.deepsampler.core.model.SampleRepository; -import java.util.Objects; - /** * This is the starting point for the definition of Samples in test classes. * @@ -41,15 +39,15 @@ private Sample() { /** - * Defines a sampled method by calling the method inside of the parameter. The returned {@link SampleBuilder} will then offer possibilities to define the Sample, + * Defines a sampled method by calling the method inside of the parameter. The returned {@link FunctionalSampleBuilder} will then offer possibilities to define the Sample, * or in other words, it offers possibilities to override the default behavior or the return value of a method. * * @param sampledMethodCall The method call that will be sampled. * @param The type of the return value and therefore the type of the Sample. - * @return A {@link SampleBuilder} which can be used to define the concrete Sample. Do not keep references to this object, it is intended to be used as a + * @return A {@link FunctionalSampleBuilder} which can be used to define the concrete Sample. Do not keep references to this object, it is intended to be used as a * fluent API only. */ - public static SampleBuilder of(final T sampledMethodCall) { + public static FunctionalSampleBuilder of(final T sampledMethodCall) { SampleDefinition currentSampleDefinition = SampleRepository.getInstance().getCurrentSampleDefinition(); SampleDefinition lastSampleDefinition = SampleRepository.getInstance().getLastSampleDefinition(); @@ -59,27 +57,9 @@ public static SampleBuilder of(final T sampledMethodCall) { SampleRepository.getInstance().setLastSampleDefinition(currentSampleDefinition); - return new SampleBuilder<>(sampledMethodCall, currentSampleDefinition); + return new FunctionalSampleBuilder<>(sampledMethodCall, currentSampleDefinition); } - /** - * Along with the subsequent method call it defines a Sample for which the framework should start to track - * how often this Sample is used in the component. This is necessary to be able to verify the invocation - * of a specific method. - * - * @param sampler the sampler for which you want to activate a method call - * @param the type of the target Class/sampler - * @return the sampler itself - */ - public static T forVerification(final T sampler) { - Objects.requireNonNull(sampler); - - if (!ProxyFactory.isProxyClass(sampler.getClass())) { - throw new NotASamplerException(sampler.getClass()); - } - - return sampler; - } /** * Along with the subsequent method call you can assert that this method call has been called @@ -95,18 +75,6 @@ public static T verifyCallQuantity(final Class cls, final Quantity quanti return ProxyFactory.createProxy(cls, new VerifySampleHandler(quantity, cls)); } - /** - * This method will set the sampleId of the last defined sampleDefinition. Mostly you - * want to set the sampleId with the Method {@link SampleBuilder#hasId(String)}. But in case of - * void-returning methods, it is not possible to create a {@link SampleBuilder}. As a consequence - * you will need to set the id with this method. - * - * @param id the id you want to set. - */ - public static void setIdToLastMethodCall(final String id) { - SampleRepository.getInstance().getCurrentSampleDefinition().setSampleId(id); - } - /** * Defines a stubbed void method by calling the method inside of a lambda. The returned {@link VoidSampleBuilder} will then offer possibilities to define the Sample, * or in other words, it offers possibilities to override the default behavior or the stubbed method. @@ -125,7 +93,7 @@ public static VoidSampleBuilder of(final VoidCall sampl try { sampledMethodCall.call(); } catch (final Exception e) { - throw new NotASamplerException("The VoidCall did throw an Exception. Did you call an unstubbed method inside of the lamda, " + + throw new NotASamplerException("The VoidCall did throw an Exception. Did you call an unstubbed method inside of the lambda, " + "instead of a method on a Sampler?", e); } diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/SampleBuilder.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/SampleBuilder.java index f032237a..09fa1d74 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/SampleBuilder.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/SampleBuilder.java @@ -1,86 +1,31 @@ -/* - * Copyright 2020 PPI AG (Hamburg, Germany) - * This program is made available under the terms of the MIT License. - */ - package de.ppi.deepsampler.core.api; -import de.ppi.deepsampler.core.model.Answer; import de.ppi.deepsampler.core.model.SampleDefinition; +import java.util.Objects; + /** - *

- * Provides a fluent API for creating a {@link SampleDefinition}. You should never create a {@link SampleBuilder} by - * yourself instead you should use {@link Sample#of(Object)}. - *

+ * Parent off all {@link SampleBuilder}s. A {@link SampleBuilder} is a Builder that is used to compose a {@link SampleDefinition} using a + * fluent API in conjunction with {@link Sample} and {@link PersistentSample}. * - *

- * With the sampleBuilder you are able to define: - *

    - *
  • A return value or returnValueSupplier
  • - *
  • A sampleId
  • - *
- *

- * The return value will be used (and evaluated) when the stubbed method will be invoked. - * The sampleId is a possibility to assign an id to the sampleDefinition. This id will be used - * in the persistence to identify the stubbed method. - *

- * - * @param type of the class you want stub + * DeepSampler defines different {@link SampleDefinition}s depending on the type of method that should be stubbed. For instance, different + * configurations are necessary for void methods and methods that return values. */ -public class SampleBuilder extends VoidSampleBuilder { +public abstract class SampleBuilder { - /** - * Create a {@link SampleBuilder} with a sampler of the class you want to build a sample for, and the sampleDefinition - * you want to extend. - * - * @param sampler the sampler {@link Sampler} - * @param sampleDefinition {@link SampleDefinition} - */ - @SuppressWarnings("unused") - public SampleBuilder(final T sampler, final SampleDefinition sampleDefinition) { - super(sampleDefinition); - } - - /** - * Makes the stubbed method return the given value when invoked. - * - * @param sampleReturnValue the return value you want to set for the sampleDefinition - */ - public void is(final T sampleReturnValue) { - getSampleDefinition().setAnswer(stubInvocation -> sampleReturnValue); - } + private final SampleDefinition sampleDefinition; /** - * In most cases it will be sufficient to define a fixed Sample as a return value for a stubbed method, but sometimes it - * is necessary to execute some logic that would compute the return value or that would even change some additional state. - * This can be done by using an Answer like so: + * Create a {@link SampleBuilder} with a {@link SampleDefinition} * - * - * Sample.of(sampler.echo(anyString())).answer(invocation -> invocation.getParameters().get(0)); - * - *

- * In essence using Answers gives free control on what a stubbed method should do. - * - * @param answer supplier you want to get evaluated when the stubbed method get invoked + * @param sampleDefinition {@link SampleDefinition} */ - @SuppressWarnings("unchecked") - public void answers(final Answer answer) { - getSampleDefinition().setAnswer((Answer) answer); + protected SampleBuilder(final SampleDefinition sampleDefinition) { + this.sampleDefinition = Objects.requireNonNull(sampleDefinition, "the SampleDefinition must not be null."); } - - - /** - * Set an id for the current SampleDefinition. - * - * @param sampleId the sampleId you want to set - * @return this - */ - public SampleBuilder hasId(final String sampleId) { - getSampleDefinition().setSampleId(sampleId); - return this; + protected SampleDefinition getSampleDefinition() { + return sampleDefinition; } - } diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/VoidSampleBuilder.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/VoidSampleBuilder.java index 25b31510..e4d14a7f 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/VoidSampleBuilder.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/api/VoidSampleBuilder.java @@ -12,12 +12,9 @@ import org.objenesis.ObjenesisStd; import org.objenesis.instantiator.ObjectInstantiator; -import java.util.Objects; - /** *

- * Provides a fluent API for creating a {@link SampleDefinition}. You should never create a {@link SampleBuilder} by - * yourself instead you should use {@link Sample#of(Object)}. + * Provides a fluent API for creating a {@link SampleDefinition} for void methods. *

* *

@@ -25,24 +22,19 @@ *

    *
  • throw Exceptions when a stubbed method is called
  • *
  • deactivate a method, so that a stubbed method does nothing when it is called
  • + *
  • delegate to the original method, so that a stubbed method does the same as the original method when it is called
  • *
*/ -public class VoidSampleBuilder { +public class VoidSampleBuilder extends SampleBuilder { - private final SampleDefinition sampleDefinition; /** * Create a {@link VoidSampleBuilder} with a {@link SampleDefinition} - * you want to extend. * * @param sampleDefinition {@link SampleDefinition} */ - public VoidSampleBuilder(final SampleDefinition sampleDefinition) { - this.sampleDefinition = Objects.requireNonNull(sampleDefinition, "the SampleDefinition must not be null."); - } - - protected SampleDefinition getSampleDefinition() { - return sampleDefinition; + protected VoidSampleBuilder(SampleDefinition sampleDefinition) { + super(sampleDefinition); } /** @@ -51,7 +43,7 @@ protected SampleDefinition getSampleDefinition() { * @param exception the Exception that will be thrown. */ public void throwsException(final Exception exception) { - sampleDefinition.setAnswer(invocation -> { + getSampleDefinition().setAnswer(invocation -> { throw exception; }); } @@ -62,7 +54,7 @@ public void throwsException(final Exception exception) { * @param exceptionClass The type of the {@link Exception} that will be thrown. The Exception is instantiated at the time when the stubbed method is called. */ public void throwsException(final Class exceptionClass) { - sampleDefinition.setAnswer(invocation -> { + getSampleDefinition().setAnswer(invocation -> { final Objenesis objenesis = new ObjenesisStd(); final ObjectInstantiator exceptionInstantiator = objenesis.getInstantiatorOf(exceptionClass); @@ -75,18 +67,18 @@ public void throwsException(final Class exceptionClass) { * * There are several situation where this might be useful. One example would be a * method that would attempt to write data in a database using values that do not comply to a foreign key, since the values are now Samples that - * don't exist in the real database. In another case it might simply be necessary to prevent a method from deleting data. + * don't exist in the real database. In another case, it might simply be necessary to prevent a method from deleting data. */ public void doesNothing() { - sampleDefinition.setAnswer(invocation -> null); + getSampleDefinition().setAnswer(invocation -> null); } /** * Calls the original unstubbed method. This is useful in conjunction with other Samples that are only supposed to be used for particular - * parameter values while all other calls of the method with different parameter values should still call the original method. + * parameter values while all other calls of the method, with different parameter values, should still call the original method. */ public void callsOriginalMethod() { - sampleDefinition.setAnswer(StubMethodInvocation::callOriginalMethod); + getSampleDefinition().setAnswer(StubMethodInvocation::callOriginalMethod); } /** @@ -102,7 +94,7 @@ public void callsOriginalMethod() { * @param answer method you want to get evaluated when the stubbed method is invoked */ public void answers(final VoidAnswer answer) { - sampleDefinition.setAnswer(stubMethodInvocation -> { + getSampleDefinition().setAnswer(stubMethodInvocation -> { answer.call(stubMethodInvocation); return null; }); diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/RecordSampleHandler.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/RecordSampleHandler.java index 36e31046..1b87dec7 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/RecordSampleHandler.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/RecordSampleHandler.java @@ -16,7 +16,7 @@ * that should be stubbed. (@see {@link de.ppi.deepsampler.core.api.Sampler}). * * Methods of the class {@link Object} are ignored. Otherwise strange effects might appear, e.g. if Object::finalize is - * called by the garbage collactor. + * called by the garbage collector. */ public class RecordSampleHandler extends ReturningSampleHandler { private final Class cls; @@ -30,6 +30,7 @@ public Object invoke(final Object self, final Method method, final Method procee if (!Object.class.equals(method.getDeclaringClass())) { final SampleDefinition sampleDefinition = createSampleDefinition(cls, method, args); SampleRepository.getInstance().add(sampleDefinition); + SampleRepository.getInstance().setMarkNextVoidSamplerForPersistence(false); } return createEmptyProxy(method.getReturnType()); diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/ReturningSampleHandler.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/ReturningSampleHandler.java index 44edc58b..b54f5b81 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/ReturningSampleHandler.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/aophandler/ReturningSampleHandler.java @@ -31,6 +31,7 @@ protected SampleDefinition createSampleDefinition(final Class cls, final Meth sampleDefinition.setParameterMatchers(parameterMatchers); sampleDefinition.setParameterValues(new ArrayList<>(Arrays.asList(args))); + sampleDefinition.setMarkedForPersistence(SampleRepository.getInstance().getMarkNextVoidSamplerForPersistence()); return sampleDefinition; } diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/api/ExecutionManager.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/api/ExecutionManager.java index a7724e02..71e72e3d 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/api/ExecutionManager.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/internal/api/ExecutionManager.java @@ -6,8 +6,10 @@ package de.ppi.deepsampler.core.internal.api; import de.ppi.deepsampler.core.api.SampleReturnProcessor; +import de.ppi.deepsampler.core.error.InvalidConfigException; import de.ppi.deepsampler.core.model.*; +import java.io.InvalidClassException; import java.util.ArrayList; import java.util.List; diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleDefinition.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleDefinition.java index cb101068..24a84f9f 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleDefinition.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleDefinition.java @@ -16,6 +16,7 @@ public class SampleDefinition { private List> parameterMatchers = new ArrayList<>(); private Answer answer; private String sampleId; + private boolean isMarkedForPersistence; public SampleDefinition(final SampledMethod sampledMethod) { this.sampledMethod = sampledMethod; @@ -74,6 +75,15 @@ public List getParameterValues() { return this.parameterValues; } + + public boolean isMarkedForPersistence() { + return isMarkedForPersistence; + } + + public void setMarkedForPersistence(boolean markedForPersistence) { + isMarkedForPersistence = markedForPersistence; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -88,6 +98,8 @@ public boolean equals(Object o) { Objects.equals(sampleId, that.sampleId); } + + @Override public int hashCode() { return Objects.hash(sampledMethod.getMethod(), parameterValues, sampleId); @@ -101,6 +113,7 @@ public String toString() { ", parameterMatchers=" + parameterMatchers + ", answer=" + answer + ", sampleId='" + sampleId + '\'' + + ", isPersistent=" + isMarkedForPersistence + '}'; } } diff --git a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleRepository.java b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleRepository.java index fda55cb2..4ad97536 100644 --- a/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleRepository.java +++ b/deepsampler-core/src/main/java/de/ppi/deepsampler/core/model/SampleRepository.java @@ -23,6 +23,8 @@ public class SampleRepository { private static Scope sampleRepositoryScope = new ThreadScope<>(); + private boolean markNextVoidSamplerForPersistence = false; + /** * Singleton Constructor. */ @@ -228,12 +230,37 @@ public List> getCurrentParameterMatchers() { return Collections.unmodifiableList(currentParameterMatchers); } + /** + * If the next newly created SampleDefinition should be marked for persistence, this getter would return true. + * This is used for void methods where the SampleDefinition is not reachable from PersistentSampler. + * + * @return true if the next SampleDefinition should be marked for persistence. + */ + public boolean getMarkNextVoidSamplerForPersistence() { + return markNextVoidSamplerForPersistence; + } + + /** + * If the next newly created SampleDefinition should be marked for persistence, markNextVoidSamplerForPersistence can be set to true. + * This is used for void methods where the SampleDefinition is not reachable from PersistentSampler. + * + * @param markNextVoidSamplerForPersistence true if the next SampleDefinition should be marked for persistence. + */ + public void setMarkNextVoidSamplerForPersistence(boolean markNextVoidSamplerForPersistence) { + this.markNextVoidSamplerForPersistence = markNextVoidSamplerForPersistence; + } + + public void clearMarkNextVoidSamplerForPersistence() { + this.markNextVoidSamplerForPersistence = false; + } + /** * Clears the actual set {@link SampleRepository#currentSample} and the {@link SampleRepository#samples} */ public void clear() { samples = new ArrayList<>(); clearCurrentParameterMatchers(); + clearMarkNextVoidSamplerForPersistence(); currentSample = null; lastSample = null; } diff --git a/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/PersistentSampleTest.java b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/PersistentSampleTest.java new file mode 100644 index 00000000..8b545ed5 --- /dev/null +++ b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/PersistentSampleTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.core.api; + +import de.ppi.deepsampler.core.error.NotASamplerException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PersistentSampleTest { + + public static final String PARAMETER_VALUE = "Blubb"; + + @BeforeEach + public void cleanUp() { + Sampler.clear(); + } + + @Test + void callOfANonSamplerIsDetectedIBeforeSamplerHasBeenDefined() { + // GIVEN + final TestService notASampler = new TestService(); + // THEN + Sampler.clear(); + assertThrows(NotASamplerException.class, () -> shouldThrowExceptionAttemptingToSampleANonSampler(notASampler)); + } + + private void shouldThrowExceptionAttemptingToSampleANonSampler(TestService notASampler) { + PersistentSample.of(notASampler.echoParameter(PARAMETER_VALUE)); + } + + @Test + void callOfANonSamplerIsDetectedAfterSamplersHasBeenDefined() { + //GIVEN + Sampler.clear(); + final TestService realTestServiceSampler = Sampler.prepare(TestService.class); + final TestService notASampler = new TestService(); + + //WHEN UNCHANGED + assertDoesNotThrow(() -> PersistentSample.of(realTestServiceSampler.echoParameter(PARAMETER_VALUE))); + + // THEN + assertThrows(NotASamplerException.class, () -> shouldThrowExceptionAttemptingToSampleANonSampler(notASampler)); + } + + @Test + void samplerForVerificationIsChecked() { + //GIVEN WHEN + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.forVerification(testServiceSampler); + + // THEN + assertThrows(NotASamplerException.class, () -> PersistentSample.forVerification("I'm not a Sampler.")); + assertThrows(NullPointerException.class, () -> PersistentSample.forVerification(null)); + } + + public static class TestService { + public String echoParameter(final String someParameter) { + return someParameter; + } + } + +} \ No newline at end of file diff --git a/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/SampleTest.java b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/SampleTest.java index a32644c8..e024fa45 100644 --- a/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/SampleTest.java +++ b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/api/SampleTest.java @@ -294,18 +294,6 @@ void voidMethodsCanBeReplacedByVoidAnswers() throws Throwable { assertEquals(1, counter.get()); } - @Test - void samplerForVerificationIsChecked() { - //GIVEN WHEN - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.forVerification(testServiceSampler); - - // THEN - assertThrows(NotASamplerException.class, () -> Sample.forVerification("I'm not a Sampler.")); - assertThrows(NullPointerException.class, () -> Sample.forVerification(null)); - } - - public static class TestService { public String echoParameter(final String someParameter) { diff --git a/deepsampler-core/src/test/java/de/ppi/deepsampler/core/internal/aophandler/VerifySampleHandlerTest.java b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/internal/aophandler/VerifySampleHandlerTest.java index e9020d96..96eb43b9 100644 --- a/deepsampler-core/src/test/java/de/ppi/deepsampler/core/internal/aophandler/VerifySampleHandlerTest.java +++ b/deepsampler-core/src/test/java/de/ppi/deepsampler/core/internal/aophandler/VerifySampleHandlerTest.java @@ -7,7 +7,7 @@ import de.ppi.deepsampler.core.api.Sampler; import de.ppi.deepsampler.core.error.VerifyException; -import de.ppi.deepsampler.core.internal.FixedQuantity; +import de.ppi.deepsampler.core.api.FixedQuantity; import de.ppi.deepsampler.core.internal.api.ExecutionManager; import de.ppi.deepsampler.core.model.SampleDefinition; import de.ppi.deepsampler.core.model.SampleRepository; diff --git a/deepsampler-junit/src/testFixtures/java/de/ppi/deepsampler/junit/TestSampleFixture.java b/deepsampler-junit/src/testFixtures/java/de/ppi/deepsampler/junit/TestSampleFixture.java index b80f5c70..9e9f02d1 100644 --- a/deepsampler-junit/src/testFixtures/java/de/ppi/deepsampler/junit/TestSampleFixture.java +++ b/deepsampler-junit/src/testFixtures/java/de/ppi/deepsampler/junit/TestSampleFixture.java @@ -5,7 +5,7 @@ package de.ppi.deepsampler.junit; -import de.ppi.deepsampler.core.api.Sample; +import de.ppi.deepsampler.core.api.PersistentSample; @SuppressWarnings("unused") public class TestSampleFixture implements SamplerFixture { @@ -15,6 +15,6 @@ public class TestSampleFixture implements SamplerFixture { @Override public void defineSamplers() { - Sample.of(testBeanSampler.getSomeInt()); + PersistentSample.of(testBeanSampler.getSomeInt()); } } diff --git a/deepsampler-persistence-json/src/main/java/de/ppi/deepsampler/persistence/json/JsonSourceManager.java b/deepsampler-persistence-json/src/main/java/de/ppi/deepsampler/persistence/json/JsonSourceManager.java index e07e8baa..cc1b8703 100644 --- a/deepsampler-persistence-json/src/main/java/de/ppi/deepsampler/persistence/json/JsonSourceManager.java +++ b/deepsampler-persistence-json/src/main/java/de/ppi/deepsampler/persistence/json/JsonSourceManager.java @@ -15,6 +15,7 @@ import de.ppi.deepsampler.persistence.json.extension.SerializationExtension; import de.ppi.deepsampler.persistence.model.PersistentModel; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -89,7 +90,11 @@ public JsonSourceManager buildWithResource(final PersistentResource resource) { } public JsonSourceManager buildWithFile(final String filePath) { - this.resource = new PersistentFile(Paths.get(filePath)); + return buildWithFile(Paths.get(filePath)); + } + + public JsonSourceManager buildWithFile(final Path filePath) { + this.resource = new PersistentFile(filePath); return new JsonSourceManager(this); } diff --git a/deepsampler-persistence-json/src/test/java/de/ppi/deepsampler/persistence/json/PersistentSamplerManagerTest.java b/deepsampler-persistence-json/src/test/java/de/ppi/deepsampler/persistence/json/PersistentSamplerManagerTest.java index 9fb4c5c3..c93e4352 100644 --- a/deepsampler-persistence-json/src/test/java/de/ppi/deepsampler/persistence/json/PersistentSamplerManagerTest.java +++ b/deepsampler-persistence-json/src/test/java/de/ppi/deepsampler/persistence/json/PersistentSamplerManagerTest.java @@ -57,6 +57,7 @@ void testSimpleApiRecord() throws Exception { void testSimpleLoad() throws Throwable { // GIVEN final SampleDefinition saySample = new SampleDefinition(new SampledMethod(InnerBean.class, InnerBean.class.getDeclaredMethod("say"))); + saySample.setMarkedForPersistence(true); SampleRepository.getInstance().add(saySample); // WHEN @@ -103,6 +104,7 @@ void testDateRecord() throws Exception { void testDateLoad() throws Throwable { // GIVEN final SampleDefinition dateSample = new SampleDefinition(new SampledMethod(DateBean.class, DateBean.class.getDeclaredMethod("now"))); + dateSample.setMarkedForPersistence(true); SampleRepository.getInstance().add(dateSample); // WHEN diff --git a/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/api/PersistentSampleManager.java b/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/api/PersistentSampleManager.java index 7ef92b06..b9210a98 100644 --- a/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/api/PersistentSampleManager.java +++ b/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/api/PersistentSampleManager.java @@ -104,14 +104,14 @@ private void mergeSamplesFromPersistenceIntoSampleRepository(final PersistentMod for (int i = 0; i < sampleRepository.size(); i++) { SampleDefinition sampler = sampleRepository.get(i); - if (sampler.getAnswer() != null) { - // It is not necessary to merge a Sampler, that already has an Answer. + if (!sampler.isMarkedForPersistence()) { continue; } List mergedPersistentSamples = createSampleDefinitionForEachPersistentSample(persistentSamples, sampler); sampleRepository.replace(i, mergedPersistentSamples); + i += mergedPersistentSamples.size() - 1; unusedPersistentSampleIds = filterUsedSampleIds(unusedPersistentSampleIds, mergedPersistentSamples); } diff --git a/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/error/NoMatchingSamplerFoundException.java b/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/error/NoMatchingSamplerFoundException.java index 2fbbc934..af5aed28 100644 --- a/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/error/NoMatchingSamplerFoundException.java +++ b/deepsampler-persistence/src/main/java/de/ppi/deepsampler/persistence/error/NoMatchingSamplerFoundException.java @@ -5,25 +5,25 @@ /** * The {@link NoMatchingSamplerFoundException} is thrown if a JSON file (or any other source of persistent Samples) - * contains Samples that don't have a matching Sampler. A Sampler is defined using {@link de.ppi.deepsampler.core.api.Sample#of(Object)}. + * contains Samples that don't have a matching Sampler. A Sampler is defined using {@link de.ppi.deepsampler.core.api.PersistentSample#of(Object)}. * * A typical cause of this Exception is, that the signature of a sampled method has changed. Maybe the method name was refactored. * Since the complete method signature is saved in the JSON (or any other persistent medium) by default, the signature in the file might * not correspond to the refactored one in the code anymore. * * You can prevent situations like this, by defining the id of a Sample manually using Sampler.of().hasId("MyId"). - * See {@link de.ppi.deepsampler.core.api.SampleBuilder#hasId(String)}. + * See {@link de.ppi.deepsampler.core.api.PersistentSampleBuilder#hasId(String)}. */ public class NoMatchingSamplerFoundException extends PersistenceException { public NoMatchingSamplerFoundException(String unusedSamplerId) { super("The persistent Sample with the id '%s' doesn't have a corresponding Sampler. " + - "Please define a Sampler using Sampler.of(...)", unusedSamplerId); + "Please define a Sampler using PersistentSample.of(...)", unusedSamplerId); } public NoMatchingSamplerFoundException(Collection unusedSamplerIds) { super("The following persistent Samples don't have a corresponding Sampler. " + - "Please define a Sampler using Sampler.of(...):\n%s", formatMissingSamplerIds(unusedSamplerIds)); + "Please define a Sampler using PersistentSample.of(...):\n%s", formatMissingSamplerIds(unusedSamplerIds)); } private static String formatMissingSamplerIds(Collection unusedSamplerIds) { diff --git a/deepsampler-persistence/src/test/java/de/ppi/deepsampler/persistence/api/PersistentSampleManagerTest.java b/deepsampler-persistence/src/test/java/de/ppi/deepsampler/persistence/api/PersistentSampleManagerTest.java index 204afb2f..241a6303 100644 --- a/deepsampler-persistence/src/test/java/de/ppi/deepsampler/persistence/api/PersistentSampleManagerTest.java +++ b/deepsampler-persistence/src/test/java/de/ppi/deepsampler/persistence/api/PersistentSampleManagerTest.java @@ -1,7 +1,7 @@ package de.ppi.deepsampler.persistence.api; -import de.ppi.deepsampler.core.api.Sample; +import de.ppi.deepsampler.core.api.PersistentSample; import de.ppi.deepsampler.core.api.Sampler; import de.ppi.deepsampler.core.error.NoMatchingParametersFoundException; import de.ppi.deepsampler.core.model.SampleDefinition; @@ -46,7 +46,7 @@ void testLoadWithComboMatcher() throws NoSuchMethodException { addMethodCall(persistentMethodCallList, Arrays.asList(givenBean, 1), true); PersistentSampleManager persistentSampleManager = new PersistentSampleManager(mockedSourceManager); - Sample.of(Sampler.prepare(TestService.class).call(combo(equalTo(new TestBean()), sameMatcher()), + PersistentSample.of(Sampler.prepare(TestService.class).call(combo(equalTo(new TestBean()), sameMatcher()), equalTo(1))).hasId("SampleId"); // WHEN @@ -92,7 +92,7 @@ void detectsCompletelyMissingSample() { addMethodCall(persistentMethodCallList, Arrays.asList(givenBean, 1), true); PersistentSampleManager persistentSampleManager = new PersistentSampleManager(mockedSourceManager); - Sample.of(Sampler.prepare(TestService.class).call(any(TestBean.class), any(Integer.class))).hasId("SampleId"); + PersistentSample.of(Sampler.prepare(TestService.class).call(any(TestBean.class), any(Integer.class))).hasId("SampleId"); // THEN assertThrows(NoMatchingSamplerFoundException.class, persistentSampleManager::load); @@ -123,7 +123,7 @@ void detectsMissingWrongParameters() { PersistentSampleManager persistentSampleManager = new PersistentSampleManager(mockedSourceManager); TestService sampler = Sampler.prepare(TestService.class); - Sample.of(sampler.call(givenBean, 4)).hasId("SampleId"); + PersistentSample.of(sampler.call(givenBean, 4)).hasId("SampleId"); // THEN assertThrows(NoMatchingParametersFoundException.class, persistentSampleManager::load); @@ -148,7 +148,7 @@ void testLoadWithMultiComboMatcher() throws NoSuchMethodException { addMethodCall(persistentMethodCallList, Arrays.asList(new TestBean(), 1), false); PersistentSampleManager persistentSampleManager = new PersistentSampleManager(mockedSourceManager); - Sample.of(Sampler.prepare(TestService.class).call(combo(equalTo(new TestBean()), equalsMatcher()), + PersistentSample.of(Sampler.prepare(TestService.class).call(combo(equalTo(new TestBean()), equalsMatcher()), combo(equalTo(1), sameMatcher()))).hasId("SampleId"); // WHEN diff --git a/deepsampler-provider-guice/src/test/java/de/ppi/deepsampler/provider/guice/GuicePersistentSamplerAspectTest.java b/deepsampler-provider-guice/src/test/java/de/ppi/deepsampler/provider/guice/GuicePersistentSamplerAspectTest.java new file mode 100644 index 00000000..ef118dcc --- /dev/null +++ b/deepsampler-provider-guice/src/test/java/de/ppi/deepsampler/provider/guice/GuicePersistentSamplerAspectTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.provider.guice; + +import com.google.inject.Guice; +import de.ppi.deepsampler.provider.common.*; +import de.ppi.deepsampler.provider.testservices.DecoupledTestService; + +import javax.inject.Inject; + + +public class GuicePersistentSamplerAspectTest extends PersistentSamplerAspectTest { + + @Inject + private TestService testService; + + + public GuicePersistentSamplerAspectTest() { + Guice.createInjector(new TestModule()).injectMembers(this); + } + + @Override + public TestService getTestService() { + return testService; + } + +} \ No newline at end of file diff --git a/deepsampler-provider-spring/src/test/java/de/ppi/deepsampler/provider/spring/SpringPersistentSamplerAspectTest.java b/deepsampler-provider-spring/src/test/java/de/ppi/deepsampler/provider/spring/SpringPersistentSamplerAspectTest.java new file mode 100644 index 00000000..b3aacea5 --- /dev/null +++ b/deepsampler-provider-spring/src/test/java/de/ppi/deepsampler/provider/spring/SpringPersistentSamplerAspectTest.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.provider.spring; + +import de.ppi.deepsampler.provider.common.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestSpringConfig.class) +public class SpringPersistentSamplerAspectTest extends PersistentSamplerAspectTest { + + @Autowired + private TestService testService; + + @Override + public TestService getTestService() { + return testService; + } + +} \ No newline at end of file diff --git a/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/PersistentSamplerAspectTest.java b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/PersistentSamplerAspectTest.java new file mode 100644 index 00000000..945e50ae --- /dev/null +++ b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/PersistentSamplerAspectTest.java @@ -0,0 +1,521 @@ +/* + * Copyright 2020 PPI AG (Hamburg, Germany) + * This program is made available under the terms of the MIT License. + */ + +package de.ppi.deepsampler.provider.common; + +import de.ppi.deepsampler.core.api.FixedQuantity; +import de.ppi.deepsampler.core.api.PersistentSample; +import de.ppi.deepsampler.core.api.Sample; +import de.ppi.deepsampler.core.api.Sampler; +import de.ppi.deepsampler.core.error.NoMatchingParametersFoundException; +import de.ppi.deepsampler.core.model.SampleRepository; +import de.ppi.deepsampler.persistence.api.PersistentSampleManager; +import de.ppi.deepsampler.persistence.api.PersistentSampler; +import de.ppi.deepsampler.persistence.error.PersistenceException; +import de.ppi.deepsampler.persistence.json.JsonSourceManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.nio.file.Path; +import java.sql.Date; +import java.time.LocalDateTime; + +import static de.ppi.deepsampler.core.api.FixedQuantity.ONCE; +import static de.ppi.deepsampler.core.api.Matchers.*; +import static de.ppi.deepsampler.persistence.api.PersistentMatchers.combo; +import static org.junit.jupiter.api.Assertions.*; + +/** + * This TestClass must be be used to test all aop-provider in order to ensure that all providers would support the same + * functionality. + */ +@SuppressWarnings("java:S5960") +@ExtendWith(TempJsonFile.class) +public abstract class PersistentSamplerAspectTest { + + public static final String VALUE_A = "Value A"; + public static final String VALUE_B = "Value B"; + private static final TestBean TEST_BEAN_A = new TestBean(); + public static final String MY_ECHO_PARAMS = "MY ECHO PARAMS"; + public static final String NO_RETURN_VALUE_SAMPLE_ID = "NoReturnValue"; + + + /** + * The {@link TestService} is a Service that is used to test method interception by a SamplerInterceptor. Since this class must be + * instantiated by the concrete Dependency Injection Framework, the creation of this instance must be done by the concrete TestCase. + * + * @return An instance of {@link TestService} that has been created in a way that enables method interception by a particular AOP-framework (i.e. Spring). + */ + public abstract TestService getTestService(); + + + @BeforeEach + public void cleanUp() { + Sampler.clear(); + } + + + + @Test + public void samplesCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.echoParameter(VALUE_A)); + PersistentSample.of(testServiceSampler.echoParameter(TEST_BEAN_A)); + + getTestService().echoParameter(VALUE_A); + getTestService().echoParameter(TEST_BEAN_A); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.echoParameter(VALUE_A)); + PersistentSample.of(testServiceSampler.echoParameter(TEST_BEAN_A)); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertNotNull(getTestService().echoParameter(VALUE_A)); + assertNotNull(getTestService().echoParameter(TEST_BEAN_A)); + assertEquals(VALUE_A, getTestService().echoParameter(VALUE_A)); + } + + + + @Test + public void voidMethodsCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.forVerification(testServiceSampler).noReturnValue(anyInt()); + + getTestService().noReturnValue(2); + getTestService().noReturnValue(3); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.forVerification(testServiceSampler).noReturnValue(anyInt()); + source.load(); + + getTestService().noReturnValue(2); + getTestService().noReturnValue(3); + + assertFalse(SampleRepository.getInstance().isEmpty()); + Sample.verifyCallQuantity(TestService.class, ONCE).noReturnValue(2); + } + + @Test + public void sqlDateCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C'))); + + getTestService().testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C')); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C'))); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(new Date(1), getTestService().testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C'))); + } + + @Test + public void listOfTestBeansReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getListOfTestBeans()); + + getTestService().getListOfTestBeans(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getListOfTestBeans()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getListOfTestBeans().size()); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getListOfTestBeans().get(0).getValue()); + } + + @Test + public void listOfStringsReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getListOfStrings()); + + getTestService().getListOfStrings(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getListOfStrings()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getListOfStrings().size()); + } + + @Test + public void setOfStringsReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getSetOfStrings()); + + getTestService().getSetOfStrings(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getSetOfStrings()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getSetOfStrings().size()); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getSetOfStrings().toArray()[0]); + } + + @Test + public void setOfTestBeansReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getSetOfTestBeans()); + + getTestService().getSetOfTestBeans(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getSetOfTestBeans()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getSetOfTestBeans().size()); + TestBean testBean = getTestService().getSetOfTestBeans().stream().findFirst().get(); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, testBean.getValue()); + } + + @Test + public void arrayOfTestBeansReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getArrayOfTestBeans()); + + getTestService().getArrayOfTestBeans(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getArrayOfTestBeans()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getArrayOfTestBeans().length); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getArrayOfTestBeans()[0].getValue()); + } + + @Test + public void arrayOfStringsReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getArrayOfStrings()); + + getTestService().getArrayOfStrings(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getArrayOfStrings()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getArrayOfStrings().length); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getArrayOfStrings()[0]); + } + + @Test + void multidimensionalArrayOfStringsCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getArrayOfStrings2d()); + + getTestService().getArrayOfStrings2d(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getArrayOfStrings2d()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + + // WHEN + String[][] result = getTestService().getArrayOfStrings2d(); + + // THEN + assertEquals(1, result.length); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, result[0][0]); + } + + + + @Test + void multidimensionalArrayOfTestBeansCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getArrayOfTestBeans3d()); + + getTestService().getArrayOfTestBeans3d(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getArrayOfTestBeans3d()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + + // WHEN + TestBean[][][] result = getTestService().getArrayOfTestBeans3d(); + + // THEN + assertEquals(1, result.length); + assertEquals(2, result[0].length); + assertEquals(1, result[0][0].length); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, result[0][0][0].getValue()); + } + + @Test + public void mapOfStringsReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getMapOfStrings()); + + getTestService().getMapOfStrings(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getMapOfStrings()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getMapOfStrings().size()); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getMapOfStrings().get(TestService.HARD_CODED_RETURN_VALUE)); + } + + @Test + public void mapOfStringsToTestBeansReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getMapOfStringsToTestBeans()); + + getTestService().getMapOfStringsToTestBeans(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getMapOfStringsToTestBeans()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getMapOfStringsToTestBeans().size()); + assertNotNull(getTestService().getMapOfStringsToTestBeans().get(TestService.HARD_CODED_RETURN_VALUE)); + + TestBean loadedTestBean = getTestService().getMapOfStringsToTestBeans().get(TestService.HARD_CODED_RETURN_VALUE); + assertEquals(TestService.HARD_CODED_RETURN_VALUE, loadedTestBean.getValue()); + } + + @Test + public void mapOfIntegersReturnValueCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getMapOfIntegers()); + + getTestService().getMapOfIntegers(); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getMapOfIntegers()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(1, getTestService().getMapOfIntegers().size()); + assertEquals(2, getTestService().getMapOfIntegers().get(1)); + } + + + @Test + public void callsWithNotMatchingParametersAreRoutedToOriginalMethod(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.getRandom(VALUE_A)); + + String hopefullyRecordedValue = getTestService().getRandom(VALUE_A); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.getRandom(VALUE_A)); + Sample.of(testServiceSampler.getRandom(anyString())).callsOriginalMethod(); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(hopefullyRecordedValue, getTestService().getRandom(VALUE_A)); + assertNotEquals(hopefullyRecordedValue, getTestService().getRandom(VALUE_B)); + } + + @Test + public void manualIdSetForRecordingAndLoadingNoCorrectDef(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); + + getTestService().echoParameter("ABC"); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.echoParameter("ABC")).hasId("MY WRONG ECHO PARAMS"); + assertThrows(PersistenceException.class, + source::load); + } + + @Test + public void manualIdSetForRecordingAndLoadingCorrectDef(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); + + getTestService().echoParameter("ABC"); + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals("ABC", getTestService().echoParameter("ABC")); + } + + @Test + public void manualIdSetForRecordingAndLoadingCorrectDefVoidMethod(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.forVerification(testServiceSampler).noReturnValue(2); + PersistentSample.setIdToLastMethodCall(NO_RETURN_VALUE_SAMPLE_ID); + + getTestService().noReturnValue(2); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.forVerification(testServiceSampler).noReturnValue(2); + PersistentSample.setIdToLastMethodCall(NO_RETURN_VALUE_SAMPLE_ID); + source.load(); + getTestService().noReturnValue(2); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(NO_RETURN_VALUE_SAMPLE_ID, SampleRepository.getInstance().getSamples().get(0).getSampleId()); + Sample.verifyCallQuantity(TestService.class, new FixedQuantity(1)).noReturnValue(2); + } + + @Test + public void localDateTimeCanBeRecordedAndLoaded(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.testLocalDateTime()); + + getTestService().testLocalDateTime(); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.testLocalDateTime()); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(LocalDateTime.of(2020, 10, 29, 10, 10, 10), getTestService().testLocalDateTime()); + } + + + + + @Test + void testComboMatcherLoadAllButAcceptOnlyA(Path tempFile) { + // GIVEN + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.echoParameter(anyString())).hasId(MY_ECHO_PARAMS); + + getTestService().echoParameter("ABC"); + + final PersistentSampleManager source = save(tempFile); + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.echoParameter(combo(anyString(), (f, s) -> f.equals("A")))).hasId(MY_ECHO_PARAMS); + + source.load(); + + // WHEN + final TestService testService = getTestService(); + String result = testService.echoParameter("A"); + String secondCallResult = testService.echoParameter("A"); + + // THEN + assertEquals("ABC", result); + assertEquals("ABC", secondCallResult); + assertThrows(NoMatchingParametersFoundException.class, () -> testService.echoParameter("B")); + } + + @Test + void testComboMatcherSecondArgument(Path tempFile) { + // GIVEN + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.methodWithThreeParametersReturningLast(anyString(), anyString(), anyString())).hasId(MY_ECHO_PARAMS); + + getTestService().methodWithThreeParametersReturningLast("BLOCK", "B", "R1"); + getTestService().methodWithThreeParametersReturningLast("BLOCK", "C", "R3"); + + final PersistentSampleManager source = save(tempFile); + clearSampleRepositoryWithAssertion(); + + PersistentSample.of(testServiceSampler.methodWithThreeParametersReturningLast(equalTo("BLOCK"), combo(anyString(), (f, s) -> f.equals("B")), combo(anyString(), (f, s) -> true))).hasId(MY_ECHO_PARAMS); + source.load(); + + // WHEN + final TestService testService = getTestService(); + String result = testService.methodWithThreeParametersReturningLast("BLOCK", "B", "ABC2"); + + // THEN + assertThrows(NoMatchingParametersFoundException.class, () -> testService.methodWithThreeParametersReturningLast("BLOCK", "C", "ABC1")); + assertEquals("R1", result); + } + + @Test + public void mixPureJavaApiAndPersistenceApi(Path tempFile) { + final TestService testServiceSampler = Sampler.prepare(TestService.class); + PersistentSample.of(testServiceSampler.testLocalDateTime()); + + getTestService().testLocalDateTime(); + + final PersistentSampleManager source = save(tempFile); + + clearSampleRepositoryWithAssertion(); + + // MIX persistence definition and pure java definition + PersistentSample.of(testServiceSampler.testLocalDateTime()); + Sample.of(testServiceSampler.echoParameter("ABC")).is("CBD"); + source.load(); + + assertFalse(SampleRepository.getInstance().isEmpty()); + assertEquals(LocalDateTime.of(2020, 10, 29, 10, 10, 10), getTestService().testLocalDateTime()); + assertEquals("CBD", getTestService().echoParameter("ABC")); + } + + private void clearSampleRepositoryWithAssertion() { + assertFalse(SampleRepository.getInstance().isEmpty()); + Sampler.clear(); + assertTrue(SampleRepository.getInstance().isEmpty()); + } + + private PersistentSampleManager save(Path pathToFile) { + final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); + source.record(); + return source; + } + +} \ No newline at end of file diff --git a/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/SamplerAspectTest.java b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/SamplerAspectTest.java index 701177d4..ccbfac01 100644 --- a/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/SamplerAspectTest.java +++ b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/SamplerAspectTest.java @@ -9,31 +9,21 @@ import de.ppi.deepsampler.core.error.InvalidConfigException; import de.ppi.deepsampler.core.error.NoMatchingParametersFoundException; import de.ppi.deepsampler.core.error.VerifyException; -import de.ppi.deepsampler.core.internal.FixedQuantity; import de.ppi.deepsampler.core.model.ExecutionRepository; import de.ppi.deepsampler.core.model.SampleRepository; -import de.ppi.deepsampler.persistence.api.PersistentSampleManager; -import de.ppi.deepsampler.persistence.api.PersistentSampler; -import de.ppi.deepsampler.persistence.error.PersistenceException; -import de.ppi.deepsampler.persistence.json.JsonSourceManager; import de.ppi.deepsampler.provider.testservices.DecoupledTestService; import de.ppi.deepsampler.provider.testservices.DecoupledTestServiceImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.sql.Date; import java.time.LocalDateTime; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import static de.ppi.deepsampler.core.api.FixedQuantity.*; import static de.ppi.deepsampler.core.api.Matchers.*; -import static de.ppi.deepsampler.core.internal.FixedQuantity.*; -import static de.ppi.deepsampler.persistence.api.PersistentMatchers.combo; import static org.junit.jupiter.api.Assertions.*; /** @@ -415,7 +405,7 @@ public void verifyMethodCalledWithoutSample() { public void verifyVoidMethod() { // CHANGE final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.forVerification(testServiceSampler).noReturnValue(1); + PersistentSample.forVerification(testServiceSampler).noReturnValue(1); //CALL getTestService().noReturnValue(1); @@ -429,7 +419,7 @@ public void verifyVoidMethod() { public void verifyVoidMethodWithWrongParameter() { // CHANGE final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.forVerification(testServiceSampler).noReturnValue(1); + PersistentSample.forVerification(testServiceSampler).noReturnValue(1); //CALL getTestService().noReturnValue(1); @@ -527,518 +517,6 @@ void behaviorOfVoidMethodCanBeChanged() { assertEquals(100, getTestService().getCounter()); } - @Test - public void samplesCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.echoParameter(VALUE_A)); - Sample.of(testServiceSampler.echoParameter(TEST_BEAN_A)); - - getTestService().echoParameter(VALUE_A); - getTestService().echoParameter(TEST_BEAN_A); - final String pathToFile = "./record/samplesCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.echoParameter(VALUE_A)); - Sample.of(testServiceSampler.echoParameter(TEST_BEAN_A)); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertNotNull(getTestService().echoParameter(VALUE_A)); - assertNotNull(getTestService().echoParameter(TEST_BEAN_A)); - assertEquals(VALUE_A, getTestService().echoParameter(VALUE_A)); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void voidMethodsCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - testServiceSampler.noReturnValue(anyInt()); - - getTestService().noReturnValue(2); - getTestService().noReturnValue(3); - final String pathToFile = "./record/voidMethodsCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - - - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - testServiceSampler.noReturnValue(anyInt()); - source.load(); - getTestService().noReturnValue(2); - getTestService().noReturnValue(3); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sample.verifyCallQuantity(TestService.class, ONCE).noReturnValue(2); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void sqlDateCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - testServiceSampler.testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C')); - - getTestService().testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C')); - final String pathToFile = "./record/sqlDateCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - testServiceSampler.testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C')); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(new Date(1), getTestService().testSqlDate(new RecTestBean(new RecTestBean(null, "A", 'C'), "B", 'C'))); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void listOfTestBeansReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getListOfTestBeans()); - - getTestService().getListOfTestBeans(); - final String pathToFile = "./record/listOfTestBeansReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getListOfTestBeans()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getListOfTestBeans().size()); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getListOfTestBeans().get(0).getValue()); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void listOfStringsReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getListOfStrings()); - - getTestService().getListOfStrings(); - final String pathToFile = "./record/listOfStringsReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getListOfStrings()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getListOfStrings().size()); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void setOfStringsReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getSetOfStrings()); - - getTestService().getSetOfStrings(); - final String pathToFile = "./record/setOfStringsReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getSetOfStrings()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getSetOfStrings().size()); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getSetOfStrings().toArray()[0]); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void setOfTestBeansReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getSetOfTestBeans()); - - getTestService().getSetOfTestBeans(); - final String pathToFile = "./record/setOfTestBeansReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getSetOfTestBeans()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getSetOfTestBeans().size()); - TestBean testBean = getTestService().getSetOfTestBeans().stream().findFirst().get(); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, testBean.getValue()); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void arrayOfTestBeansReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getArrayOfTestBeans()); - - getTestService().getArrayOfTestBeans(); - final String pathToFile = "./record/arrayOfTestBeansReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getArrayOfTestBeans()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getArrayOfTestBeans().length); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getArrayOfTestBeans()[0].getValue()); - - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void arrayOfStringsReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getArrayOfStrings()); - - getTestService().getArrayOfStrings(); - final String pathToFile = "./record/arrayOfStringsReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getArrayOfStrings()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getArrayOfStrings().length); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getArrayOfStrings()[0]); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - void multidimensionalArrayOfStringsCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getArrayOfStrings2d()); - - getTestService().getArrayOfStrings2d(); - final String pathToFile = "./record/multidimensionalArrayCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getArrayOfStrings2d()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - - // WHEN - String[][] result = getTestService().getArrayOfStrings2d(); - - // THEN - assertEquals(1, result.length); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, result[0][0]); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - void multidimensionalArrayOfTestBeansCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getArrayOfTestBeans3d()); - - getTestService().getArrayOfTestBeans3d(); - final String pathToFile = "./record/multidimensionalArrayOfTestBeansCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getArrayOfTestBeans3d()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - - // WHEN - TestBean[][][] result = getTestService().getArrayOfTestBeans3d(); - - // THEN - assertEquals(1, result.length); - assertEquals(2, result[0].length); - assertEquals(1, result[0][0].length); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, result[0][0][0].getValue()); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void mapOfStringsReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getMapOfStrings()); - - getTestService().getMapOfStrings(); - final String pathToFile = "./record/mapOfStringsReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getMapOfStrings()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getMapOfStrings().size()); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, getTestService().getMapOfStrings().get(TestService.HARD_CODED_RETURN_VALUE)); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void mapOfStringsToTestBeansReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getMapOfStringsToTestBeans()); - - getTestService().getMapOfStringsToTestBeans(); - final String pathToFile = "./record/mapOfStringsToTestBeansReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getMapOfStringsToTestBeans()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getMapOfStringsToTestBeans().size()); - assertNotNull(getTestService().getMapOfStringsToTestBeans().get(TestService.HARD_CODED_RETURN_VALUE)); - - TestBean loadedTestBean = getTestService().getMapOfStringsToTestBeans().get(TestService.HARD_CODED_RETURN_VALUE); - assertEquals(TestService.HARD_CODED_RETURN_VALUE, loadedTestBean.getValue()); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void mapOfIntegersReturnValueCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getMapOfIntegers()); - - getTestService().getMapOfIntegers(); - final String pathToFile = "./record/mapOfIntegersReturnValueCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getMapOfIntegers()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(1, getTestService().getMapOfIntegers().size()); - assertEquals(2, getTestService().getMapOfIntegers().get(1)); - - Files.delete(Paths.get(pathToFile)); - } - - - @Test - public void callsWithNotMatchingParametersAreRoutedToOriginalMethod() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.getRandom(VALUE_A)); - - String hopefullyRecordedValue = getTestService().getRandom(VALUE_A); - - final String pathToFile = "./record/samplesCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.getRandom(VALUE_A)); - Sample.of(testServiceSampler.getRandom(anyString())).callsOriginalMethod(); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertNotNull(getTestService().getRandom(VALUE_A)); - assertEquals(hopefullyRecordedValue, getTestService().getRandom(VALUE_A)); - assertNotEquals(hopefullyRecordedValue, getTestService().getRandom(VALUE_B)); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void manualIdSetForRecordingAndLoadingNoCorrectDef() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); - - getTestService().echoParameter("ABC"); - final String pathToFile = "./record/manualIdSetForRecordingAndLoading.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.echoParameter("ABC")).hasId("MY WRONG ECHO PARAMS"); - assertThrows(PersistenceException.class, - source::load); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void manualIdSetForRecordingAndLoadingCorrectDef() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); - - getTestService().echoParameter("ABC"); - final String pathToFile = "./record/manualIdSetForRecordingAndLoadingCorrectDef.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.echoParameter("ABC")).hasId(MY_ECHO_PARAMS); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals("ABC", getTestService().echoParameter("ABC")); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void manualIdSetForRecordingAndLoadingCorrectDefVoidMethod() throws IOException { - Sampler.clear(); - - final TestService testServiceSampler = Sampler.prepare(TestService.class); - testServiceSampler.noReturnValue(2); - Sample.setIdToLastMethodCall(NO_RETURN_VALUE_SAMPLE_ID); - - getTestService().noReturnValue(2); - - final String pathToFile = "./record/manualIdSetForRecordingAndLoadingCorrectDef.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - testServiceSampler.noReturnValue(2); - Sample.setIdToLastMethodCall(NO_RETURN_VALUE_SAMPLE_ID); - source.load(); - getTestService().noReturnValue(2); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(NO_RETURN_VALUE_SAMPLE_ID, SampleRepository.getInstance().getSamples().get(0).getSampleId()); - Sample.verifyCallQuantity(TestService.class, new FixedQuantity(1)).noReturnValue(2); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void localDateTimeCanBeRecordedAndLoaded() throws IOException { - Sampler.clear(); - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.testLocalDateTime()); - - getTestService().testLocalDateTime(); - - final String pathToFile = "./record/localDateTimeCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - Sample.of(testServiceSampler.testLocalDateTime()); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(LocalDateTime.of(2020, 10, 29, 10, 10, 10), getTestService().testLocalDateTime()); - Files.delete(Paths.get(pathToFile)); - } @Test public void threadScopeWorks() throws ExecutionException, InterruptedException { @@ -1167,87 +645,4 @@ void testPostProcessSampleReturnLocal() { assertEquals(VALUE_B, resultEcho); assertNull(localDateTime); } - - @Test - void testComboMatcherLoadAllButAcceptOnlyA() throws IOException { - // GIVEN - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.echoParameter(anyString())).hasId(MY_ECHO_PARAMS); - - getTestService().echoParameter("ABC"); - final String pathToFile = "./record/comboMatcherSingleArgument.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - Sampler.clear(); - Sample.of(testServiceSampler.echoParameter(combo(anyString(), (f, s) -> f.equals("A")))).hasId(MY_ECHO_PARAMS); - - source.load(); - - // WHEN - final TestService testService = getTestService(); - String result = testService.echoParameter("A"); - String secondCallResult = testService.echoParameter("A"); - - // THEN - assertEquals("ABC", result); - assertEquals("ABC", secondCallResult); - assertThrows(NoMatchingParametersFoundException.class, () -> testService.echoParameter("B")); - - Files.delete(Paths.get(pathToFile)); - } - - @Test - void testComboMatcherSecondArgument() throws IOException { - // GIVEN - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.methodWithThreeParametersReturningLast(anyString(), anyString(), anyString())).hasId(MY_ECHO_PARAMS); - - getTestService().methodWithThreeParametersReturningLast("BLOCK", "B", "R1"); - getTestService().methodWithThreeParametersReturningLast("BLOCK", "C", "R3"); - - final String pathToFile = "./record/comboMatcherTwoArguments.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - Sampler.clear(); - - Sample.of(testServiceSampler.methodWithThreeParametersReturningLast(equalTo("BLOCK"), combo(anyString(), (f, s) -> f.equals("B")), combo(anyString(), (f, s) -> true))).hasId(MY_ECHO_PARAMS); - source.load(); - - // WHEN - final TestService testService = getTestService(); - String result = testService.methodWithThreeParametersReturningLast("BLOCK", "B", "ABC2"); - - // THEN - assertThrows(NoMatchingParametersFoundException.class, () -> testService.methodWithThreeParametersReturningLast("BLOCK", "C", "ABC1")); - assertEquals("R1", result); - Files.delete(Paths.get(pathToFile)); - } - - @Test - public void mixPureJavaApiAndPersistenceApi() throws IOException { - Sampler.clear(); - final TestService testServiceSampler = Sampler.prepare(TestService.class); - Sample.of(testServiceSampler.testLocalDateTime()); - - getTestService().testLocalDateTime(); - - final String pathToFile = "./record/localDateTimeCanBeRecordedAndLoaded.json"; - final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile)); - source.record(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - Sampler.clear(); - assertTrue(SampleRepository.getInstance().isEmpty()); - - // MIX persistence definition and pure java definition - Sample.of(testServiceSampler.testLocalDateTime()); - Sample.of(testServiceSampler.echoParameter("ABC")).is("CBD"); - source.load(); - - assertFalse(SampleRepository.getInstance().isEmpty()); - assertEquals(LocalDateTime.of(2020, 10, 29, 10, 10, 10), getTestService().testLocalDateTime()); - assertEquals("CBD", getTestService().echoParameter("ABC")); - Files.delete(Paths.get(pathToFile)); - } - } \ No newline at end of file diff --git a/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/TempJsonFile.java b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/TempJsonFile.java new file mode 100644 index 00000000..1f152264 --- /dev/null +++ b/deepsampler-provider/src/testFixtures/java/de/ppi/deepsampler/provider/common/TempJsonFile.java @@ -0,0 +1,36 @@ +package de.ppi.deepsampler.provider.common; + +import org.junit.jupiter.api.extension.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * A small convenience-extension, that creates a name for a json-file depending on the name of a test-method, and also deletes the file after + * the test has completed. The files are stored in the folder ./record. + */ +public class TempJsonFile implements ParameterResolver, BeforeEachCallback, AfterEachCallback { + + private Path tempFile; + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return parameterContext.getParameter().getType().equals(Path.class); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + return tempFile; + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + Files.deleteIfExists(tempFile); + } + + @Override + public void beforeEach(ExtensionContext extensionContext) { + tempFile = Paths.get("./record", extensionContext.getDisplayName() + ".json"); + } +}