Random numbers in java generated JMeter testplan - jmeter

I programmaticaly generate my jmeter test plans in java code.
HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
threadGroupHashTree.add(loopController);
HashTree threadGroupHashTree;
String employeeId = "1";
HTTPSamplerProxy hs = HttpSampler.createHttpSampler(data, "http://test.de/employee/" + employeeId, "GET", "");
threadGroupHashTree.add(hs);
Then I start this testplan:
StandardJMeterEngine jmeter = setupJMeter(threadGroupHashTree);
jmeter.configure(threadGroupHashTree);
jmeter.run();
It's works. Now I need to send requests with different employeeId (random). In JMeter GUI we can use random functions for randomize our tests.
Provides JMeter API such functionality? How can we randomize our requests? Or we must replace LoopController with for loops?

You can use JMeter's __Random() function normally like:
String employeeId = "${__Random(1,999,)}"
Just make sure to have ApacheJMeter_functions JAR in your project classpath
You can use RandomUtils class like
String employeeId = String.valueOf(org.apache.commons.lang3.RandomUtils.nextInt(1,1000));
You can use ThreadLocalRandom class like
String employeeId = String.valueOf(java.util.concurrent.ThreadLocalRandom.current().nextInt(1,1000));
Any of the approaches will return a random number each time it will be called.
See Five Ways To Launch a JMeter Test without Using the JMeter GUI article and jmeter-from-code example project to learn more about creating JMeter tests programmatically.

Related

How to store values from a while loop to a list as a property in JMeter

Is there a way to add each session Id that is retrieved from a Loop Controller to a list and assign it to a property for use in the following thread group? Below I used a couple of Dummy Sampler to explain my requirement.
I had 3 users stored in a list to retrieve 3 session ids in the setUp Thread Group.
JSR223 PreProcessor
List usernames = Arrays.asList('Peter', 'Alex', 'Mary');
props.put('accounts', usernames);
I was able to read a username from this property to get a session id in the response accordingly per iteration in the Loop Controller.
"sessionId": "this_is_my_session_id-${__groovy(props.get('accounts').get(${__jm__LoopController__idx} % 3),)}-${__jm__LoopController__idx} "
I parsed the 3 session ids out by a JSR223 PostProcessor
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper();
def response = jsonSlurper.parseText(prev.getResponseDataAsString());
def json = JsonOutput.toJson(response.sessionId)
def sessionId = new JsonSlurper().parseText(json)
log.info('The session id is:' + sessionId)
ArrayList<String> sessionIds = new ArrayList<String>();
props.put("sessionIds", sessionIds.add(sessionId))
I needed to add these 3 session ids to a list and assign it to a property so that I can use one session id inside the property per VU/thread in the following Thread Group. But it didn't work as expected. It threw error saying No such property: sessionIds
${__groovy(props.get(sessionIds).get(${__jm__UseSession__idx} % 3),)}
We don't know what do you "expect"
Most probably the problem is here:
props.put("sessionIds", sessionIds.add(sessionId))
Collection.add() function returns a boolean value so it puts true to the sessionIds property instead of the real value of the ArrayList.
So I believe you need to change it to something like:
sessionIds.add(sessionId)
props.put("sessionIds", sessionIds)
if you're going to run the JSR223 Test Element in the loop you can also reconsider the way you're initializing the sessionIds and implement the following logic:
If sessionIds property exists - read its value
If it doesn't exist - create a new ArrayList
Something like:
ArrayList<String> sessionIds = props.get("sessionIds") ?: new ArrayList<String>()
More information on Groovy scripting in JMeter: Apache Groovy: What Is Groovy Used For?

Jmeter- Log values to CSV file

I have used below code to log values to CSV. With this code I am not able to get header names, it directly logging values to firstname, lastname without header. I am expecting the output file with header and values. For example: Can some please let me know whats missing
firstname lastname
Test Jmeter
firstNameoutput = vars.get(“firstName”)
lastNameoutput = vars.get(“lastName”)
resultPath = vars.get(“resultsheetFilePath”)
FileOutputStream file= new FileOutputStream(resultPath, true);
PrintStream printOutputData = new PrintStream(file);
this.interpreter.setOut(printOutputData);
Var responseCode=prev.getResponseCode();
If (responseCode.equals(“200”){
print(“PASS”+”+firstName+”,”+lastName);
}
Just write firstname and lastname as the first line of the CSV file somewhere in setUp Thread Group.
As since JMeter 3.1 Groovy is the recommended scripting option add a JSR223 Sampler to the setUp Thread group and put the following code there:
new File(vars.get('resultsheetFilePath')).text = 'firstname,lastname' + System.getProperty('line.separator')
This will create the file with the header at the beginning of the test and you can write the values later.

Spring Boot: what is the best strategy to unit test repository methods?

We have a lot of methods with joins and fetches that look like :
#Query(
"select new com.company.user.entity.DTO.UserBillingDTO(" +
"u.id as id, " +
"u.firstName as firstName, " +
"u.lastName as lastName, " +
"e.tokenId as tokenId," +
"u.companyId as companyId," +
"e.id as entityId, " +
"u.userName as userName, " +
"u.locale as locale) " +
"from User as u " +
"join u.profiles as p " +
"join p.entity as e " +
"where u.id = :userId")
UserBillingDTO findUserForBilling(#Param("userId") String userId);
I d like to cover such methods with tests and see if our HQL queries are returning the expected results.
The question is how can i populate my local database easily to test the outcome of our methods?
One obvious way would be to create entities in the test setup using
code. But I am afraid the readability of this test will be very low.
Another idea that comes to my mind is to dump a database from our
test platform, use it to setup tests and then only run queries to
check the results.
Can you think of anything else? How could I write a maintainable test suite that is easy-to-follow for the team?
EDIT:
The post Using JUnit to perform an insert
suggests DBUnit
Populating using the repository
One possibility is to create the records within your test. This is what you described as the obvious solution. For your current code, you could do something like this:
#Test
public void findUserForBilling() {
repository.saveAll(Lists.newArrayList(
new User("1", "John", "Doe", "JDoe123", new Profile(..., new ProfileEntity(1, "token123"))),
new User("2", "Jane", "Doe", "TheJane", new Profile(..., new ProfileEntity(2, "token234")))));
UserBillingDTO dto = repository.findUserForBilling("1");
assertThat(dto.getId()).isEqualTo("1");
// ...
}
While in some cases your test data might take some place, in this case, it's only a few lines, which isn't any more than a usual unit test preparation/given scenario.
Be aware: In this type of test, you are not testing your entity mapping. If there's an issue within your entity mapping, you won't be able to tell using these tests.
Populating using a SQL file
Another possibility is to use a separate SQL file, for example user-dataset.sql within src/test/resources:
insert into user (id, firstname, lastname) values ("1", "John", "Doe");
insert into user (id, firstname, lastname) values ("2", "Jane", "Doe");
--- ...
And then you can include that dataset in your test by using the #Sql annotation, for example:
#RunWith(SpringRunner.class)
#DataJpaTest
#Transactional(propagation = Propagation.NOT_SUPPORTED)
#Sql("classpath:user-dataset.sql") // Add this
public class UserRepositoryTest {
// ...
}
You can add the #Sql annotation to your test class, or even to a single test method, for example:
#Test
#Sql("classpath:user-dataset.sql") // Add this
public void findUserForBilling() {
UserBillingDTO dto = repository.findUserForBilling("1");
assertThat(dto.getId()).isEqualTo("1");
// ...
}
Be aware: If I'm not mistaken, Spring will create the datasource once for the test class. If you execute your dataset for each test method, you'll have to add a delete statement to delete all existing records first.
If you just want one dataset for all your tests, you could even further simplify and name your dataset data.sql. Since Spring boot will automatically execute a data.sql file on your classpath if you're using an in-memory database (which could be useful for your tests), you don't even need the #Sql annotation.
Populating using DbUnit
Another approach is to choose a framework like DbUnit, which allows you to define your dataset in an XML format. You can use it in combination with Spring Test DBUnit to integrate more easily with Spring.
You have to keep in mind though that it's not as easily set up as using #Sql and you need to know an additional language, namely the XML structure for setting up datasets.
If you are not using database specific features, e.g. custom SQL functions specific to Oracle, you can set up an embedded database in the #SpringBootTest test. Annotate the test class with #AutoConfigureTestDatabase annotation e.g. to replace the default application DataSource bean with an embedded in-memory database:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
You can use either Flyway or Liquibase to populate the database as per 81.5 Use a Higher-level Database Migration Tool chapter. As per docs:
You can also use Flyway to provide data for specific scenarios. For example, you can place test-specific migrations in src/test/resources and they are run only when your application starts for testing. Also, you can use profile-specific configuration to customize spring.flyway.locations so that certain migrations run only when a particular profile is active. For example, in application-dev.properties, you might specify the following setting:

Junit Mockito:How to Pass parameters: Arraylist,int value to Rest Junit API

I am writing junit for a rest API , I have junit test method with below snippet , Can any one tell me how we can pass the ArrayList and int type of data when we are using mockito. Can you please tell me.
Test invocation eg:
` List<MyUser> myUserList = new ArrayList<MyUser>();
MyUser user1 = new UsrHelper().create();
MyUser user2 = new UsrHelper().create();
myUserList.add(user1);
myUserList.add(user2);
MvcResult result =mockMvc.perform(post("/test1/test2/test3").contentType(MediaType.APPLICATION_JSON).content(JsonUtils.toJsonString(myUserList)).param("myuserId", 1234).param("id", "abcd123")).andExpect(status().isOk()).andReturn();`
In the above myUserList is the arraylist and myuserId - is int value. Please let me know.
I got the soultion , the mapping parameter was passed correctly. Wrong parameter name (myuserId) was passed. Got fixed the problem.Thank you

How to send "empty" variable into JMeter

I have some functional tests created via JMeter. It is pretty huge but i can't handle one simple check.
I generate properties using BSF pre processor with help of JS. Parameter (lets call it "payment_fee") should be generated only if other parameter (lets call it "role") has a value = 1 .In this case we post pre generated integer into payment_fee and everything works well. But if role =2 then we should post nothing into payment_fee.
The problem is, i don't know how to say to JMeter: In case if role = 1 use variable with pre generated payment_fee but if role = 2, you shouldn't use this variable so just post an empty value for payment_fee . Server waits for an integer so empty string or NULL had been rejected.
For more clarification:
I will try to explain more clear.
Here is a part of my code
var role = Math.floor(Math.random()*3+1)
var paymentType = ["creditcard","cash"]
var randomPay = installerType[Math.floor(Math.random()*installerType.length)];
var payment = "";
var paymentFee;
if (role == 1){
payment+=randomPay,
paymentFee = Math.floor((Math.random() * 999) + 1) / 10.00
}
vars.put("role", role);
vars.put("payment", payment);
vars.put("paymentFee", paymentFee);
And if role == 1 i should post paymentFee value. Like this - http://prntscr.com/b50kk1 BUT! if role == 2 || role == 3 I should remove this value, so it should be like this http://prnt.sc/b50l82
I don't fully understand what you're trying to do as your 2 statements clash:
But if role =2 then we should post nothing into payment_fee
Server waits for an integer so empty string or NULL had been rejected
You should know few bits about JMeter properties:
Properties are global for the whole JVM. Once you set property it will "live" until you exit JMeter.
Properties can be accesses by all threads of all Thread Groups.
So it might be the case when you define property earlier or by another thread and expect it to be not set later on.
Also BSF PreProcessor and JavaScript isn't the best combination from performance perspective, consider switching to JSR223 PreProcessor and Groovy language.

Resources