How to test Apache HttpClient RequestConfig values are set correctly? No public getters present - testing

I have this class to configure a HttpClient instance:
package com.company.fraud.preauth.service.feignaccertifyclient;
import com.company.fraud.preauth.config.ProviderClientConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
#Slf4j
#Configuration
#RequiredArgsConstructor
public class FeignClientConfig {
private final ProviderClientConfig providerClientConfig;
public HttpClient buildHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RequestConfig.Builder requestBuilder = RequestConfig.custom();
requestBuilder.setConnectTimeout(providerClientConfig.getConnectionTimeout());
requestBuilder.setConnectionRequestTimeout(providerClientConfig.getConnectionRequestTimeout());
requestBuilder.setSocketTimeout(providerClientConfig.getSocketTimeout());
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
return HttpClientBuilder.create()
.setMaxConnPerRoute(providerClientConfig.getMaxConnectionNumber())
.setDefaultRequestConfig(requestBuilder.build())
.setSSLContext(builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build())
.build();
}
}
How to unit test this class, to see into the resulted HttpClient that these values are correctly set?
From the httpClient I cannot get access to its RequestConfig.
I am aware of these two posts:
How do I test a private function or a class that has private methods, fields or inner classes?
(the number of upvotes in this question shows that it is a concurrent and controversial topic in testing, and my situation may offer an example that why we should look into the inner state of an instance in testing, despite that it is private)
Unit test timeouts in Apache HttpClient
(it shows a way of adding an interceptor in code to check configure values, but I don't like it because I want to separate tests with functional codes)
Is there any way? I understand that this class should be tested, right? You cannot blindly trust it to work; and checking it "notNull" seems fragile to me.
This link may point me to the right direction:
https://dzone.com/articles/testing-objects-internal-state
It uses PowerMock.Whitebox to check internal state of an instance.

So I have checked into PowerMock.Whitebox source code, and it turns out reflection is used internally. And, as PowerMock is said to be not compatible with JUnit 5 yet(till now), and I don't want to add another dependency just for testing, so I will test with reflection.
package com.company.fraud.preauth.service.feignaccertifyclient;
import com.company.fraud.preauth.config.PreAuthConfiguration;
import com.company.fraud.preauth.config.ProviderClientConfig;
import com.company.fraud.preauth.config.StopConfiguration;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.lang.reflect.Field;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = {
PreAuthConfiguration.class,
StopConfiguration.class,
})
public class FeignClientConfigTest {
#Mock
private ProviderClientConfig providerClientConfig;
#Test
#DisplayName("should return HttpClient with defaultConfig field filled with values in providerClientConfig")
public void shouldReturnHttpClientWithConfiguredValues() throws Exception {
// given
when(providerClientConfig.getConnectionRequestTimeout()).thenReturn(30000);
when(providerClientConfig.getConnectionTimeout()).thenReturn(30);
when(providerClientConfig.getMaxConnNumPerRoute()).thenReturn(20);
when(providerClientConfig.getSocketTimeout()).thenReturn(10);
FeignClientConfig feignClientConfig = new FeignClientConfig(providerClientConfig);
// when
HttpClient httpClient = feignClientConfig.buildHttpClient();
// then
// I want to test internal state of built HttpClient and this should be checked
// I tried to use PowerMock.Whitebox, but then I found it uses reflection internally
// I don't want to introduce another dependency, and PowerMock is said not to be compatible with JUnit 5, so..
Field requestConfigField = httpClient.getClass().getDeclaredField("defaultConfig");
requestConfigField.setAccessible(true);
RequestConfig requestConfig = (RequestConfig)requestConfigField.get(httpClient);
assertThat(requestConfig.getConnectionRequestTimeout(), equalTo(30000));
assertThat(requestConfig.getConnectTimeout(), equalTo(30));
assertThat(requestConfig.getSocketTimeout(), equalTo(10));
}
}
Also, I answer the first question in OP about when to test private members in a class here

Whitebox was working for me. As it is not documented here I'm adding my version:
in my case wanted to test that the timeout is different from 0 to avoid deadlock
HttpClient httpClient = factory.getHttpClient();
RequestConfig sut = Whitebox.getInternalState(httpClient, "defaultConfig");
assertNotEquals(0, sut.getConnectionRequestTimeout());
assertNotEquals(0, sut.getConnectTimeout());
assertNotEquals(0, sut.getSocketTimeout());

Related

How to start a #Bean with custom parameters after an event had happened with spring for tests?

I am working on adding RepositoryTests with TestContainers framework for a project that uses R2dbc and I am running into the following situation:
1 - On the main project I set r2dbc url (with port and hostname) on application.yaml file and spring data manages everything and things just work.
2 - On the Tests however, I am using TestContainers framework more specifically DockerComposeContainer which I use to create a mocked container using docker-compose.test.yaml file with the databases I need.
3 - This container creates a port number on the go I define a port number on my docker-compose file but the port number that DockerComposeContainer will provide me is random and changes everytime I run the tests, what makes having a static url on application-test.yaml not an option anymore.
So I need to dinamically create this bean R2dbcEntityTemplate at run time and only after the DockerComposeContainer will give me the port number. So my application can connect to the correct port and things should work as expected.
I tried to create this class:
package com.wayfair.samworkgroupsservice.adapter
import io.r2dbc.mssql.MssqlConnectionConfiguration
import io.r2dbc.mssql.MssqlConnectionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.ConstructorArgumentValues
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.GenericBeanDefinition
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Profile
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.r2dbc.dialect.SqlServerDialect
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.stereotype.Component
#Component
#Profile("test")
class TemplateFactory(
#Autowired val applicationContext: ApplicationContext
) {
private val beanFactory = applicationContext.autowireCapableBeanFactory as BeanDefinitionRegistry
fun registerTemplateBean(host: String, port: Int) {
val beanDefinition = GenericBeanDefinition()
beanDefinition.beanClass = R2dbcEntityTemplate::class.java
val args = ConstructorArgumentValues()
args.addIndexedArgumentValue(
0,
DatabaseClient.builder()
.connectionFactory(connectionFactory(host, port))
.bindMarkers(SqlServerDialect.INSTANCE.bindMarkersFactory)
.build()
)
args.addIndexedArgumentValue(1, DefaultReactiveDataAccessStrategy(SqlServerDialect.INSTANCE))
beanDefinition.constructorArgumentValues = args
beanFactory.registerBeanDefinition("R2dbcEntityTemplate", beanDefinition)
}
// fun entityTemplate(host: String = "localhost", port: Int = 1435) =
// R2dbcEntityTemplate(
// DatabaseClient.builder()
// .connectionFactory(connectionFactory(host, port))
// .bindMarkers(SqlServerDialect.INSTANCE.bindMarkersFactory)
// .build(),
// DefaultReactiveDataAccessStrategy(SqlServerDialect.INSTANCE)
// )
private fun connectionFactory(host: String, port: Int) =
MssqlConnectionFactory(
MssqlConnectionConfiguration.builder()
.host(host)
.port(port)
.username("sa")
.password("Password123##?")
.build()
)
}
And this is how my db initiliser looks like:
package com.wayfair.samworkgroupsservice.adapter.note
import com.wayfair.samworkgroupsservice.adapter.DBInitializerInterface
import com.wayfair.samworkgroupsservice.adapter.TemplateFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.testcontainers.containers.DockerComposeContainer
import org.testcontainers.containers.wait.strategy.Wait
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import java.io.File
#Testcontainers
class NoteTagDBInitializer : DBInitializerInterface {
#Autowired
override lateinit var client: R2dbcEntityTemplate
#Autowired
lateinit var factory: TemplateFactory
override val sqlScripts = listOf(
"db/note/schema.sql",
"db/note/reset.sql",
"db/note/data.sql"
)
init {
factory.registerTemplateBean(
cont.getServiceHost("test-db-local_1", 1433),
cont.getServicePort("test-db-local_1", 1433)
)
}
companion object {
#Container
val cont: KDockerComposerContainer = KDockerComposerContainer("docker-compose.test.yml")
.withExposedService(
"test-db-local_1", 1433,
Wait.forListeningPort()
)
.withLocalCompose(true)
.also {
it.start()
val porttt = it.getServicePort("test-db-local_1", 1433)
print(porttt)
}
class KDockerComposerContainer(yamlFile: String) :
DockerComposeContainer<KDockerComposerContainer>(File(yamlFile))
}
}
I am not getting errors when trying to start this template factory with no useful error message,
But to be honest I don't know anymore if am putting effort into the correct solution, does anyone have any insight on how to pull this off or if I am doing anything wrong here?
So to summarise for production app it is fine, it starts based off of the url on application.yaml file and that's it, but for tests I need something dinamic with ports that will change everytime.
Thank you in advance ))
Spring already has a solution for your problem.
If you're using a quite recent Spring version (>= 5.2.5), you should utilize #DynamicPropertySource in order to adjust your test configuration properties with a dynamic value of the container database port. Read official spring documentation for more details and kotlin code examples.
If you're stuck with an older Spring version, the interface you need is ApplicationContextInitializer. See this spring github issue for a small example.

Modify remote driver URL at runtime

I have a project which is based on the serenity-bdd/serenity-cucumber-starter project. I'm using test-containers to start a couple of Docker containers as well as a Selenium Grid container to run the test against.
new GenericContainer<>(SELENIUM_IMAGE)
...
.withExposedPorts(SELENIUM_CONTAINER_PORT, SELENIUM_CONTAINER_NOVNC_PORT)
...
);
When the tests start, test-containers will ramp up the containers and bind random host ports to all exposed ports of the containers.
Because of that, I cannot define a fixed value in serenity.conf for the url of the remote driver
webdriver.remote.url = "http://localhost:????/wd/hub"
Thus I need a way to set webdriver.remote.url programmatically.
One option would be to use the FixedHostPortGenericContainer, which allows you define the host port on which the container exposed port will be bound to.
I'd rather would like to use a different approach though, as the developers state that
While this works, we strongly advise against using fixed ports, since this will automatically lead to integrated tests (which are an anti pattern).
So the question is: How can I modify the value of webdriver.remote.url at runtime? Is there any option provided by serenity-bdd to reload the net.thucydides.core.util.SystemEnvironmentVariables at runtime?
Faced recently the same issue, but was lucky enough to find a solution:
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import net.serenitybdd.core.webdriver.driverproviders.FirefoxDriverCapabilities;
import net.thucydides.core.guice.Injectors;
import net.thucydides.core.util.EnvironmentVariables;
import net.thucydides.core.webdriver.DriverSource;
public class CustomWebDriverFactory implements DriverSource {
#Override
public WebDriver newDriver() {
try {
String ip = "your_dynamic_ip";
return new RemoteWebDriver(
new URL("http://" + ip + ":4444/wd/hub"),
new FirefoxDriverCapabilities(Injectors.getInjector().getProvider(EnvironmentVariables.class).get()).getCapabilities());
}
catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
#Override
public boolean takesScreenshots() {
return true;
}
}
So you have to add such factory implementation and define in serenity.properties:
webdriver.driver = provided
webdriver.provided.type = mydriver
webdriver.provided.mydriver = <your_factory_package>.CustomWebDriverFactory
thucydides.driver.capabilities = mydriver

Selenium framework and test data in json

I am just completed a test automation using with selenium. And I want to know about how to keep the test data separately in json format.
Can you please tell me how to write test data in the page object pattern.
Here I am using multiple packages. One is for locators identification, another is for page factory for initializing elements, and the other is package utilities for common values like get URL. I also have a test package for testing a login module.
What I don't know is where should I put the test data class ?
I want to keep the test data separately. Not scattering all over the script. Keep the test data in Json. And read it from there where ever it is necessary.
Still I'm getting confusing about where Should I put the json format
And also I am selenium code doesn't follow a framework. I did n't follow any frameworks. Anybody please tell me about frameworks ?
Frameworks are : Data driven, keyword driven, hybrid and modular. which framework is most people using , because and why ?
As a tester should have knowledge about all frameworks ?
I am following page object design pattern:
Page object :
package pageobjects;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
public class HomePage
{
#FindBy(how= How.NAME, using = "username")
WebElement username;
#FindBy(how=How.NAME, using = "password")
WebElement password;
#FindBy(how=How.XPATH, using="//*[#id=\'login-container\']/form/div[3]/div/p/input[1]" )
WebElement button;
//enter username
public void userLogin(String user, String pass)
{
username.sendKeys(user);
password.sendKeys(pass);
button.click();
}
}
Steps:
package steps;
import org.openqa.selenium.support.PageFactory;
import pageobjects.ClientPage;
import pageobjects.HomePage;
import util.DriverManager;
public class LoginSteps
{
public HomePage Login(String nam, String pas) {
HomePage homePageObj = PageFactory.initElements(DriverManager.driver, HomePage.class);
homePageObj.userLogin(nam,pas);
return homePageObj;
}
}
Util:
package util;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class DriverManager
{
public static WebDriver driver;
String baseUrl="//http:qms";
public DriverManager()
{
System.setProperty("webdriver.chrome.driver","/home/naveen/chromedriver");
driver=new ChromeDriver();
driver.get(baseUrl);
driver.manage().window().maximize();
}
}
Login Test :
package login;
import org.testng.Assert;
import org.testng.annotations.*;
import pageobjects.HomePage;
import steps.LoginSteps;
import util.DriverManager;
import static util.DriverManager.driver;
public class loginTest
{
#BeforeSuite(groups = {"regression"})
public void initDriver(){
DriverManager manager = new DriverManager();
}
#DataProvider(name= "login")
public static java.lang.Object[][] loginData(){
return new Object[][]{{"geoso","1"},{"ges","2"},{"geo","1"}};
}
#Test(dataProvider = "login")
public void verifyValidLoginWithDataProvider(String userName,String password)
{
LoginSteps loginSteps= new LoginSteps();
HomePage ex=loginSteps.Login(userName,password);
Assert.assertTrue(driver.getPageSource().contains("Hello Naveen"));
}
}
Here is the scenario of json format Please tell me how to write the code?
first open URL and go to login page then .
login
{
"username" :"ertte"
password: "34"
}
"Admin"
"users"
"add users"
"username" :"tsrt"
"password":"sdfgsdrfg"
name:"gfgf"
nickname:"fgsdgf"
role:"client"
email:"sdfsd#gmail.com"
submit
}}
There are so many different frameworks you can use now in combination with selenium.
I use Cucumber [BDD].
You can write your scenarios as regular sentences and Gherkin will transfer them in a methods. Sentences can have parameters or list of a parameters.
You have execution control for your test at two, let call it top levels. You can choose which feature file you want to ran.
Second execution filter can be build by using tags. For e.g. #smoketest #regression and so on.
You can use also TestNG. You have .xml file where you can make your setup. Execute particular clases, methods, prioretize test, make test dependencies, skip tests, and have full control over execution.
There are lot more I assume but these two are the most popular.

Getting phone call logs using API Bridge - J2ME

I'm trying to get to my nokia symbian S60 5th (NOKIA 5800) phone call logs using API Bridge. I followed the documentation from Nokia site but application doesn't work. The code is in Java ME. The problem is that I can't Initialize the API Bridge Midlet. This is the code. Thank you
package mobileapplication3;
import apibridge.*;
import apibridge.entities.*;
import com.sun.lwuit.*;
//
import java.util.*;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.location.Coordinates;
import javax.microedition.location.Criteria;
import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationProvider;
import javax.microedition.lcdui.TextBox;
//
/*import apibridge.LocationService;
import apibridge.LoggingService;
import apibridge.APIBridge;
import apibridge.HTTPManager;
import apibridge.MediaManagementService;
import apibridge.URLEncoder;
import apibridge.NewFileService;
import apibridge.entities.*;*/
import javax.microedition.midlet.*;
public class Midlet extends MIDlet implements CommandListener {
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
private Command callLogCommand = new Command("Calllog", Command.ITEM, 2);
private final TextBox tbox = new TextBox("Result", "", 3000, 0);
public Midlet() {
tbox.addCommand(exitCommand);
tbox.addCommand(callLogCommand);
tbox.setCommandListener(this);
APIBridge apiBridge = APIBridge.getInstance();
apiBridge.Initialize(this);
tbox.setString("Prova ...");
}
A MIDlet doesn't get started by its constructor. It gets started by the startApp() method.
So try moving everything inside your constructor, into a function called startApp().
public Midlet() {
}
public void startApp() {
tbox.addCommand(exitCommand);
tbox.addCommand(callLogCommand);
tbox.setCommandListener(this);
APIBridge apiBridge = APIBridge.getInstance();
apiBridge.Initialize(this);
tbox.setString("Prova ...");
}
See if that helps.

Dynamic Method Invocation and JAXBElement Type on CXF

I wrote the small application below to list all the methods and of a soap service using Apache CXF library. This application lists all the methods of the service, but as it is seen on the output when you run this application, input parameters and return types of the service methods are JAXBElement for the complex types. I want cxf not to generate JAXBElement, instead I want the complex types in their original classes generated on runtime. As it is said on http://s141.codeinspot.com/q/1455881 , it can be done by setting generateElementProperty property's value to false for wsdl2java utility of cxf library, but I couldn't find the same parameter for dynamic method invocation with cxf library. I want to obtain input parameters and return types in their original types.
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import org.apache.cxf.binding.Binding;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingMessageInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceModelUtil;
public class Main {
public static void main(String[] args) {
URL wsdlURL = null;
try {
wsdlURL = new URL("http://path_to_wsdl?wsdl");
} catch (MalformedURLException e) {
e.printStackTrace();
}
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsdlURL, classLoader);
Binding binding = client.getEndpoint().getBinding();
BindingInfo bindingInfo = binding.getBindingInfo();
Collection<BindingOperationInfo> operations = bindingInfo.getOperations();
for(BindingOperationInfo boi:operations){
OperationInfo oi = boi.getOperationInfo();
BindingMessageInfo inputMessageInfo = boi.getInput();
List<MessagePartInfo> parts = inputMessageInfo.getMessageParts();
System.out.println("function name: "+oi.getName().getLocalPart());
List<String> inputParams = ServiceModelUtil.getOperationInputPartNames(oi);
System.out.println("input parameters: "+inputParams);
for(MessagePartInfo partInfo:parts){
Class<?> partClass = partInfo.getTypeClass(); //here we have input parameter object on each iteration
Method[] methods = partClass.getMethods();
for(Method method:methods){
System.out.println("method: "+method);
Class<?>[] paramTypes = method.getParameterTypes();
for(Class paramType:paramTypes){
System.out.println("param: "+paramType.getCanonicalName());
}
Class returnType = method.getReturnType();
System.out.println("returns: "+returnType.getCanonicalName());
}
System.out.println("partclass: "+partClass.getCanonicalName());
}
}
System.out.println("binding: " + binding);
}
}
Create a binding file that looks like:
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateElementProperty="false">
<xjc:simple />
</jaxb:globalBindings>
</jaxb:bindings>
and pass that into the JaxWsDynamicClientFactory via the createClient method that takes the List of binding files.