I am using JBehave for writing BDD Integration tests.
Problem: JBehave clears state of objects (instance variables) while executing individual steps
Code:
StepDefinition:
public class StepDefs {
private String str;
#Given("step represents a precondition to an $event")
public void given(String event){
str=event;
System.out.println("Given: "+str);
}
#When("step represents the occurrence of the event")
public void when() {
System.out.println("When: "+str);
}
#Then("step represents the outcome of the event")
public void then() {
}
}
Story:
Sample story
Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development
Scenario: A scenario is a collection of executable steps of different type
Given step represents a precondition to an event
When step represents the occurrence of the event
Then step represents the outcome of the event
JBehaveJUnitTestRunner:
#RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {
private CrossReference xref = new CrossReference();
public JBehaveTestsRunner() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
.useStoryReporterBuilder(
new StoryReporterBuilder().withFormats(Format.HTML, Format.CONSOLE, Format.STATS)
.withViewResources(viewResources).withFailureTrace(true).withFailureTraceCompression(false)
.withCrossReference(xref));
}
#Override
public InjectableStepsFactory stepsFactory() {
return new ScanningStepsFactory(configuration(), "stepdefs");
}
#Override
public List<String> storyPaths() {
StoryFinder finder = new StoryFinder();
return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Simple.story"), null);
}
}
Actual Output:
Processing system properties {}
Using controls EmbedderControls[batch=false,skip=false,generateViewAfterStories=true,ignoreFailureInStories=true,ignoreFailureInView=true,verboseFailures=true,verboseFiltering=false,storyTimeouts=300,threads=1,failOnStoryTimeout=false]
(BeforeStories)
Running story stories/Simple.story
Sample story
(stories/Simple.story)
Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development
Scenario: A scenario is a collection of executable steps of different type
**Given: event**
Given step represents a precondition to an event
**When: null**
When step represents the occurrence of the event
Then step represents the outcome of the event
(AfterStories)
Generating reports view to 'C:\WORKING\lunaworkspace\pkeautomation\target\jbehave' using formats '[html, console, stats, junitscenarioreporter]' and view properties '{decorateNonHtml=true}'
log4j:WARN No appenders could be found for logger (freemarker.cache).
log4j:WARN Please initialize the log4j system properly.
Reports view generated with 3 stories (of which 1 pending) containing 2 scenarios (of which 1 pending)
As can be seen in the output: In the Given step I am accepting a string argument which i am initializing it to instance variable "str", whilst printing the value to console I can see it successfully. But when the second step i.e When step executes I am getting null as the value of instance variable "str". How can I make JBehave to not clear state of objects after executing individual steps?
For anyone coming looking for an answer for this question I did found proper resolution to this by taking help from the JBehave google group community. The solution is quite simple instead of using ScanningStepFactory Use InstanceStepsFactory and that should persist the state of the objects. Link to the discussion: Google Group discussion
Snippet for anyone coming here for answer:
package runner;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.CrossReference;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
//import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
//import org.jbehave.core.steps.ScanningStepsFactory;
import org.junit.runner.RunWith;
import de.codecentric.jbehave.junit.monitoring.JUnitReportingRunner;
import stepdefs.StepDefs;
//import stepdefs.BarStep;
//import stepdefs.FooStep;
#RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {
private CrossReference xref = new CrossReference();
public JBehaveTestsRunner() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
.useStoryReporterBuilder(new StoryReporterBuilder()
.withFormats(Format.HTML, Format.CONSOLE, Format.STATS).withViewResources(viewResources)
.withFailureTrace(true).withFailureTraceCompression(false).withCrossReference(xref));
}
/*#Override
public List<CandidateSteps> candidateSteps() {
return new InstanceStepsFactory(configuration(), new FooStep(), new BarStep(), new StepDefs())
.createCandidateSteps();
}*/
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new StepDefs());
// return new ScanningStepsFactory(configuration(), "stepdefinitions");
}
#Override
public List<String> storyPaths() {
StoryFinder finder = new StoryFinder();
return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Sample.story"),
null);
}
}
It's been a while since I used JBehave. It may be that you're creating a new ScanningStepsFactory for each stepsFactory() call. Try creating just one of those in the constructor then pass that instance back so that you're not creating a new one for each call.
And if that fails, try using an InstanceStepsFactory as in the example here:
public abstract class NoughtsAndCrossesStory extends JUnitStory {
public NoughtsAndCrossesStory() {
Configuration configuration = new MostUsefulConfiguration()
.useStoryPathResolver(new UnderscoredCamelCaseResolver(""))
.useStoryReporterBuilder(new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(this.getClass()))
.withDefaultFormats()
.withFormats(CONSOLE, TXT)
.withFailureTrace(true));
useConfiguration(configuration);
WindowControl windowControl = new WindowControl();
addSteps(new InstanceStepsFactory(configuration,new GridSteps(windowControl), new BeforeAndAfterSteps(windowControl)).createCandidateSteps());
}
}
You'll need to create some kind of persistent repository object in which to hold your string (in the example above, windowControl persists).
public class BeforeAndAfterSteps extends Steps {
private final WindowControl windowControl;
public BeforeAndAfterSteps(WindowControl windowControl) {
this.windowControl = windowControl;
}
#BeforeScenario
public void beforeScenarios() throws Exception {
windowControl.reset();
}
#AfterScenario
public void afterScenarios() throws Exception {
windowControl.destroy();
}
}
This allows you not only to persist state across steps, but between scenarios. Please note that that's generally considered a bad practice; I'm using this here to ensure that state is not persisted between scenarios, but in theory you could use it to, for instance, initialize default data before running your test suite.
Related
I have written some unit tests for a static method. The static method takes only one argument. The argument's type is a final class. In terms of code:
public class Utility {
public static Optional<String> getName(Customer customer) {
// method's body.
}
}
public final class Customer {
// class definition
}
So for the Utility class I have created a test class UtilityTests in which I have written tests for this method, getName. The unit testing framework is TestNG and the mocking library that is used is Mockito. So a typical test has the following structure:
public class UtilityTests {
#Test
public void getNameTest() {
// Arrange
Customer customerMock = Mockito.mock(Customer.class);
Mockito.when(...).thenReturn(...);
// Act
Optional<String> name = Utility.getName(customerMock);
// Assert
Assert.assertTrue(...);
}
}
What is the problem ?
Whereas the tests run successfully locally, inside IntelliJ, they fail on Jenkins (when I push my code in the remote branch, a build is triggered and unit tests run at the end). The error message is sth like the following:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class
com.packagename.Customer Mockito
cannot mock/spy because :
- final class
What I tried ?
I searched a bit, in order to find a solution but I didn't make it. I note here that I am not allowed to change the fact that Customer is a final class. In addition to this, I would like if possible to not change it's design at all (e.g. creating an interface, that would hold the methods that I want to mock and state that the Customer class implements that interface, as correctly Jose pointed out in his comment). The thing that I tried is the second option mentioned at mockito-final. Despite the fact that this fixed the problem, it brake some other unit tests :(, that cannot be fixed in none apparent way.
Questions
So here are the two questions I have:
How that is possible in the first place ? Shouldn't the test fail both locally and in Jenkins ?
How this can be fixed based in the constraints I mentioned above ?
Thanks in advance for any help.
An alternative approach would be to use the 'method to class' pattern.
Move the methods out of the customer class into another class/classes, say CustomerSomething eg/CustomerFinances (or whatever it's responsibility is).
Add a constructor to Customer.
Now you don't need to mock Customer, just the CustomerSomething class! You may not need to mock that either if it has no external dependencies.
Here's a good blog on the topic: https://simpleprogrammer.com/back-to-basics-mock-eliminating-patterns/
How that is possible in the first place? Shouldn't the test fail both locally and in Jenkins ?
It's obviously a kind of env-specifics. The only question is - how to determine the cause of difference.
I'd suggest you to check org.mockito.internal.util.MockUtil#typeMockabilityOf method and compare, what mockMaker is actually used in both environments and why.
If mockMaker is the same - compare loaded classes IDE-Client vs Jenkins-Client - do they have any difference on the time of test execution.
How this can be fixed based in the constraints I mentioned above?
The following code is written in assumption of OpenJDK 12 and Mockito 2.28.2, but I believe you can adjust it to any actually used version.
public class UtilityTest {
#Rule
public InlineMocksRule inlineMocksRule = new InlineMocksRule();
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void testFinalClass() {
// Given
String testName = "Ainz Ooal Gown";
Client client = Mockito.mock(Client.class);
Mockito.when(client.getName()).thenReturn(testName);
// When
String name = Utility.getName(client).orElseThrow();
// Then
assertEquals(testName, name);
}
static final class Client {
final String getName() {
return "text";
}
}
static final class Utility {
static Optional<String> getName(Client client) {
return Optional.ofNullable(client).map(Client::getName);
}
}
}
With a separate rule for inline mocks:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.internal.util.MockUtil;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class InlineMocksRule implements TestRule {
private static Field MOCK_MAKER_FIELD;
static {
try {
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
VarHandle modifiers = lookup.findVarHandle(Field.class, "modifiers", int.class);
MOCK_MAKER_FIELD = MockUtil.class.getDeclaredField("mockMaker");
MOCK_MAKER_FIELD.setAccessible(true);
int mods = MOCK_MAKER_FIELD.getModifiers();
if (Modifier.isFinal(mods)) {
modifiers.set(MOCK_MAKER_FIELD, mods & ~Modifier.FINAL);
}
} catch (IllegalAccessException | NoSuchFieldException ex) {
throw new RuntimeException(ex);
}
}
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
Object oldMaker = MOCK_MAKER_FIELD.get(null);
MOCK_MAKER_FIELD.set(null, Plugins.getPlugins().getInlineMockMaker());
try {
base.evaluate();
} finally {
MOCK_MAKER_FIELD.set(null, oldMaker);
}
}
};
}
}
Make sure you run the test with the same arguments. Check if your intellij run configurations match the jenkins. https://www.jetbrains.com/help/idea/creating-and-editing-run-debug-configurations.html. You can try to run test on local machine with the same arguments as on jenkins(from terminal), if it will fail that means the problem is in arguments
I am working in java, I am not able to find help regarding populating String with tags, for example, I have the following string
Dear Mr {{person_name}}, Your current status is {{current_status}}.
I want to make string at run time like below
Dear Mr Pitter, Your current status is active.
I am working in spring boot.
Here is a working example using org.antlr.stringtemplate.StringTemplate since you mentioned trying that yourself. It works by replacing every instance of {{ and }} with $
package com.demo.template;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.language.DefaultTemplateLexer;
public class StringTemplatePoc {
public String stringsForTags(String personName, String currentStatus) {
StringTemplate stringForTags =
new StringTemplate(
"Dear Mr {{person_name}}, Your current status is {{current_status}}."
.replaceAll("(\\{\\{|}})", "\\$"),
DefaultTemplateLexer.class);
stringForTags.setAttribute("person_name", personName);
stringForTags.setAttribute("current_status", currentStatus);
return stringForTags.toString();
}
}
And a test that runs successfully
package com.demo.template;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class StringTemplatePocTest {
private final StringTemplatePoc poc = new StringTemplatePoc();
#Test
public void stringsForTagsShouldReplacePersonNameAndStatus() {
assertThat(poc.stringsForTags("Pitter", "active"))
.isEqualTo("Dear Mr Pitter, Your current status is active.");
}
}
I'm sure, this question can be answered very quickly by a experienced Java-developer. But as I am not that familiar with Java I don't get how to source out the #Config part of Selenium in Java. It would be optimal, if I could have a config-file or -class where I can put the data (browser, website etc.) on the one hand and on the other hand the test-files.
Here is an example of a test file:
package com.example_test.selenium;
import io.ddavison.conductor.Browser;
import io.ddavison.conductor.Config;
import io.ddavison.conductor.Locomotive;
import org.junit.Test;
#Config(
browser = Browser.CHROME,
url = "http://example.com"
)
public class test_a_Home extends Locomotive {
#Test
public void testifExists() {
validatePresent(site_a_Home.EL_NEWCUSTOMERBANNER);
}
}
Now I would like to have a seperate file called tests.java where I can call the "test_a_Home"-function. If I try it just with
package com.example_test.selenium;
public class tests {
test_a_Home test = new test_a_Home();
test.testifExists();
}
I am receiving the error, that "testifExists()" cannot be resolved.
I tried changing the public void testifExists() to public int testifExists() and tried to call it with int res = test.testifExists(); in the class tests but this does not work either, as I receive the error java.lang.Exception: Method testNewCustomersBannerExists() should be void.
I would be very happy, if anyone could help me. If you need more information please feel free to mention it. Thank you.
If you want your design to be like this, then you need to organize your tests as such:
public class BasePage {
public Locomotive test;
public BasePage(Locomotive baseTest) {
test = baseTest;
}
}
public class test_a_Home extends BasePage {
public test_a_Home(Locomotive baseTest) {
super(baseTest);
}
public void testifExists() {
test.validatePresent(site_a_Home.EL_NEWCUSTOMERBANNER);
}
}
Then your test class, i'd recommend creating a base class as well:
#Config(
browser = Browser.CHROME,
url = "http://example.com"
)
public class BaseTest extends Locomotive {}
And then your test class:
public class tests extends BaseTest {
test_a_Home test = new test_a_Home(this);
#Test
public void testHomePage() {
test.testIfExists();
}
}
Also you state state:
I don't get how to source out the #Config part of Selenium in Java.
Please make sure you know, that using Conductor abstracts you from the Selenium API.. It just wraps it. #Config does not belong to Selenium, it belongs to Conductor.
I'm creating a small java service that returns a list of restaurants depending on the selected place.
Data is retrieved from Riak using com.basho.riak:riak-client:2.0.0 and the read operation is wrapped in a TenacityCommand.
Important classes are described below and I would be happy if you could assist me in creating a solid and simple unit test.
Commands are created using a factory:
package service.command.factory;
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import domain.Place;
import service.command.FetchRestaurantsCommand;
public class FetchRestaurantsCommandFactory {
private final RiakClient riakClient;
private final Namespace namespace;
public FetchRestaurantsCommandFactory(final RiakClient riakClient, final Namespace namespace) {
this.riakClient = riakClient;
this.namespace = namespace;
}
public FetchRestaurantsCommand create(final Place place) {
Location location = new Location(namespace, place.getName());
FetchValue riakCommand = new FetchValue.Builder(location).build();
return new FetchRestaurantsCommand(riakClient, riakCommand);
}
}
And the command looks like this:
package service.command;
import java.util.Optional;
import service.command.keys.WhereToEatDependencyKeys;
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.api.commands.kv.FetchValue.Response;
import com.yammer.tenacity.core.TenacityCommand;
import domain.Restaurant;
import domain.RestaurantList;
public class FetchRestaurantsCommand extends TenacityCommand<Optional<RestaurantList>>{
private final RiakClient riakClient;
private final FetchValue fetchValue;
public FetchRestaurantsCommand(RiakClient riakClient, FetchValue fetchValue) {
super(WhereToEatDependencyKeys.RIAK_GET_RESTAURANTS);
this.fetchValue = fetchValue;
this.riakClient = riakClient;
}
#Override
protected Optional<RestaurantList> run() throws Exception {
Response response = riakClient.execute(fetchValue);
return Optional.ofNullable(response.getValue(RestaurantList.class));
}
#Override
protected Optional<RestaurantList> getFallback() {
return Optional.of(RestaurantList.createFallback(new Restaurant("My failure suggestion")));
}
}
The above classes are used like:
Place place = // Created from url parameter
RiakClient riakClient = // created on start using the app's conf
Namespace namespace = // created on start using the app's conf
FetchRestaurantsCommandFactory factory = new FetchRestaurantsCommandFactory(riakClient, namespace);
FetchRestaurantsCommand command = factory.create(place);
return command.execute();
Apart from the features provided by TenacityCommand, how should I assert that my system fetches data as expeceted?
My initial idea was to mock a RiakClient to return a predefined FetchValue.Response and then make assertions on the resulting RestaurantList.
Unfortunately its not possible to instantiate or Mockito.mock a FetchValue.Response due to its design.
The accepted answer in How to mock riak java client? describes why Mockito won't work.
As far a I understood you want to write unit test. So you want to test that assuming some Response whether Optional<RestaurantList> instance is constructed correctly or not.
What I can think of is to wrap riakClient.execute(fetchValue); in a protected (or package private) helper function like:
Response fetch() {
return riakClient.execute(fetchValue);
}
Then in your test you can inherit from FetchRestaurantsCommand and override fetch function by returning any Response
Now, you can write any test to see whether the conversion of given Response to Optional<RestaurantList> behaves as expected or not.
If you need entire code and my explanation is not clear enough let me know to provide it.
I ended up using PowerMock as suggested by #gontard. See my unit test on GitHub: FetchRestaurantsCommandTest.java
I considered to create a fake/mock RiakClient in the com.basho.riak.client package. Such class could hopefully instantiate the Response object in the same way as the real client does. It would probably work for fetchValue but it would grow too big when involving more advanced Riak concepts s.a. siblings.
We are having test automation project in selenum with testng. We have completed half of the automation project and running it successfully. Now, we have to add new feature to create flow of testing with multiple test methods. So, for this I have to create java ui which will display all the methods created for test, based on user requirement the methods will be selected for test flow, now when user click on save or run button I have to create the testng.xml file which will run the test for selected methods.
Now Questions I have is as follow:
1. Is it possible to generate dynamic xlm file?
2. In test class I have multiple methods which are depended on other methods of class, so if user select depended methods on ui how I should manage those methods?
3. How to show created methods from all the class on ui to generate flow?
4. Is it good to call bat file to run the generated flow?
I would appreciate your inputs.
Thanks,
Karim
Is it possible to generate dynamic xlm file?
Yes. We do this, we generate the xml from a text file which lists the classes they want to run.
In test class I have multiple methods which are depended on other methods of class, so if user select depended methods on ui how I should manage those methods?
Well you can add the dependent methods when the user selects a method automatically, in which case your code will need to have a map of dependent methods.
How to show created methods from all the class on ui to generate flow?
4. Is it good to call bat file to run the generated flow?
- I didnt understand this part.
if i understanded your question you need to generate xml files that would be tested or something like this
for [xml] (How to generate xml in Java?) or (Fastest and most efficient way to create XML)
all you have to do to create a class similar to XMLEncoder and XMLDecoder wich use beans.
Using below code you can get all the method with #Test annotation....
---
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Set;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
import org.testng.annotations.Test;
import org.testng.internal.ClassHelper;
import org.testng.internal.annotations.AnnotationHelper;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.internal.annotations.JDK15AnnotationFinder;
public class FindTestMethodsInTestClass {
public static void main(String[] args) {
IAnnotationFinder finder = new JDK15AnnotationFinder(new DummyTransformer());
Set<Method> allMethods = ClassHelper.getAvailableMethods(MyFirstTestClass.class);
for (Method eachMethod : allMethods) {
ITestAnnotation value = AnnotationHelper.findTest(finder, eachMethod);
if (value != null) {
System.out.println(eachMethod.getName() + " is a test method");
} else {
System.out.println(eachMethod.getName() + " is NOT a test method");
}
}
}
public static class DummyTransformer implements IAnnotationTransformer {
#SuppressWarnings("rawtypes")
#Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor,
Method testMethod) {
}
}
public static class MyFirstTestClass {
public void foobar() {
}
#Test
public void foo() {
}
#Test
public void bar() {
}
}
}
The reference of above code is from: https://groups.google.com/forum/#!topic/testng-users/WbR2kxpT-7o