In a function, I am creating an instance of CredentialsProvider and calling its authenticate method.
val credentialsProvider = new CredentialsProvider(authInfoRepository, passwordHasherRegistory)
val loginInfoFuture: Future[LoginInfo] = credentialsProvider.authenticate(credentials)
In my unit test, I am creating a mock of CredentialsProvider.
val mockCredentialsProvider = mock(classOf[CredentialsProvider])
and in my test case, I am mocking a value when authenticate is called.
when(testEnv.mockCredentialsProvider.authenticate(ArgumentMatchers.any[Credentials])).thenReturn(
Future{
println(s"mocked credentials provider will return ${testEnv.loginInfo}")
testEnv.loginInfo}
)
When I run my test case, it crashes. Looking at the stack trace, it seems that the actual implementation of authenticate gets called instead of simply returning a value.
at com.mohiva.play.silhouette.persistence.repositories.DelegableAuthInfoRepository.find(DelegableAuthInfoRepository.scala:51)
at com.mohiva.play.silhouette.impl.providers.PasswordProvider.authenticate(PasswordProvider.scala:73)
at com.mohiva.play.silhouette.impl.providers.PasswordProvider.authenticate$(PasswordProvider.scala:72)
at com.mohiva.play.silhouette.impl.providers.CredentialsProvider.authenticate(CredentialsProvider.scala:46)
at com.mohiva.play.silhouette.impl.providers.CredentialsProvider.$anonfun$authenticate$1(CredentialsProvider.scala:66)
Why my mocked code isn't working?
Related
How can I unit test this code?
private ODataQueryResult buildAndExecuteQuery(String path String entity,
String sapClient, String sapLanguage) {
ODataQuery query = ODataQueryBuilder
.withEntity(path, entity)
.withHeader("sap-client", sapClient, true)
.withHeader("sap-language", sapLanguage, true)
.withoutMetadata()
.build();
return query.execute();
}
More precisely: How can I verify that my code calls all the right functions, for example does not forget to call withoutMetadata or set the required headers?
Unfortunately, ODataQueryBuilder and ODataQuery are classes, not interfaces. which makes mocking tricky. ODataQueryBuilder is even final, disabling mocking completely. Also, the chain starts with a static method withEntity which can also not be mocked.
Are there helpers that allow me to spy on behavior or mock data, similar to the MockUtil described in https://blogs.sap.com/2017/09/19/step-12-with-sap-s4hana-cloud-sdk-automated-testing/?
You are right, the structure of those classes make them hard to mock, but as they are part of the "SAP Cloud Platform SDK for Service Development" we have no way to change them.
Other approaches might be:
If you want to stay with the Unit Test approach you might want to have a look at https://github.com/powermock/powermock. This would allow you to mock final and static classes and methods. However, I have never used it personally, so I'm not sure how easy/comfortable to use it is.
If you also would see an integration test suiting you could consider using http://wiremock.org/docs/getting-started/. With that you would be able to setup a "Mock Server", preparing responses for defined requests and with that verify the content of any HTTP call made by your test.
We use WireMock in the SAP Cloud SDK and also provide some integration into our SDK via the MockUtil contained in our testutil-core module.
I hope this helps a bit!
Partial solution is to simulate executing the ODataQuery on a mock HttpClient.
First, the original method needs to be taken apart into two independent parts, one for building the query, the other for executing it. This is good design anyway, so no big problem:
private ODataQuery buildQuery(String path, String entity,
String sapClient, String sapLanguage) {
return ODataQueryBuilder
.withEntity(path, entity)
.withHeader("sap-client", sapClient, true)
.withHeader("sap-language", sapLanguage, true)
.withoutMetadata()
.build();
}
private ODataResponse executeQuery(ODataQuery query) {
return query.execute();
}
The buildQuery method can now be tested as follows:
#Test
public void addsSapLanguageToHeader() throws ODataException, IOException {
ODataQuery query = cut.buildQuery("api/v2", "business-partners", "", "fr");
HttpUriRequest request = getRequest(query);
assertContainsHeader(request, "sap-language", "fr");
}
The method getRequest produces a fake HttpClient that stubs all methods required to get query.execute(httpClient) to work. It stores the actual request and returns it for further inspection. Sample implementation with Mockito:
private HttpUriRequest getRequest(ODataQuery query) throws ODataException, IOException {
// stub methods to make code work
HttpResponse response = mock(HttpResponse.class);
when(httpClient.execute(any())).thenReturn(response);
StatusLine statusLine = mock(StatusLine.class);
when(response.getStatusLine()).thenReturn(statusLine);
HttpEntity entity = mock(HttpEntity.class);
when(response.getEntity()).thenReturn(entity);
InputStream inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
when(entity.getContent()).thenReturn(inputStream);
Header[] headers = new Header[0];
when(response.getAllHeaders()).thenReturn(headers);
// simulate the execution of the query
query.execute(httpClient);
// grab the original argument from the mock for inspection
ArgumentCaptor<HttpUriRequest> captor = ArgumentCaptor.forClass(HttpUriRequest.class);
verify(httpClient).execute(captor.capture());
HttpUriRequest request = captor.getValue();
return request;
}
This solution is far from perfect, of course.
First, the amount of code needed to make this work alone shows how fragile this test will be over time. Whenever the CloudSDK decides to add a method or validation to the call sequence, this test will break. Note also that the test is invasive, by testing a private method, while gold standards say we should test only public methods.
Second, the method executeQuery can still not be tested. Execution paths also differ, because the test code uses the .execute(httpClient) variant to run the query, while the original code uses the .execute(destinationName) variant. The two happen to share code, but this may change over time.
The project is written using Play framework and Scala language.
I have implemented compile time dependency.
I have followed this example from Play:
https://github.com/playframework/play-scala-compile-di-example
Looking at the MyApplicationLoader.scala:
import play.api._
import play.api.routing.Router
class MyApplicationLoader extends ApplicationLoader {
private var components: MyComponents = _
def load(context: ApplicationLoader.Context): Application = {
components = new MyComponents(context)
components.application
}
}
class MyComponents(context: ApplicationLoader.Context)
extends BuiltInComponentsFromContext(context)
with play.filters.HttpFiltersComponents
with _root_.controllers.AssetsComponents {
lazy val homeController = new _root_.controllers.HomeController(controllerComponents)
lazy val router: Router = new _root_.router.Routes(httpErrorHandler, homeController, assets)
}
and the following line of code:
lazy val homeController = new _root_.controllers.HomeController(controllerComponents)
my understanding is that there is only one instance of HomeController created the first time HomeController is called.
And that instance lives as long as the application lives. Are these statements correct?
The HomeController in my application looks like that:
class HomeController{
val request = // some code here
val workflowExecutionResult = Workflow.execute(request)
}
So Workflow is of type object and not class.
The Workflow looks like that:
object Workflow {
def execute(request: Request) = {
val retrieveCustomersResult = RetrieveCustomers.retrieve()
// some code here
val createRequestResult = CreateRequest.create(request)
// some code here
workflowExecutionResult
}
}
So Workflow calls a few domain services and each domain service is of type object and not class.
All values inside the domain services are immutable, I am using vals everywhere.
Is this enough to ensure thread safety?
I am asking as I'm used to writing C# Web APIs where a HomeController would look like that:
class HomeControllerInSeeSharpProject{
// some code here
var request = new Request() // more code here
var workflow = new WorkflowInSeeSharpProject()
var workflowExecutionResult = workflow.execute(request)
}
and a Workflow would look like that:
public class WorkflowInSeeSharpProject {
public execute(Request request) {
var retrieveCustomers = new RetrieveCustomers()
var retrieveCustomersResult = retrieveCustomers.retrieve()
// some code here
var createRequest = new CreateRequest()
var createRequestResult = createRequest.create(request)
// some code here
return workflowExecutionResult
}
}
So in a C# project every time a HomeControllerInSeeSharpProject is called a new instance of WorkflowInSeeSharpProject is created and all the domain services
are also newed-up and then I can be sure that state cannot be shared between separate threads. So I am afraid that because my Scala Workflow
and domain services are of type object and not class that there could be a situation where two requests are sent into the HomeController
and state is shared between those two threads.
Can this be the case? Is my application not thread safe?
I have read that objects in Scala are not thread safe since there is only single instance of them. However I have also read that although
they are not thread safe using vals will make the application thread safe...
Or maybe Play itself has a way to deal with that problem?
Because your are using compile time dependency injection, you control the number of instances created, and in your case HomeController is created only once. As requests come in, this single instance will be shared between threads so indeed you have to make sure it is thread-safe. All the dependencies of HomeController will also need to be thread-safe, thus object Workflow has to be thread-safe. Currently, Workflow is not publicly exposing any shared state, so it is thread-safe. In general, val definitions within object are thread-safe.
In effect HomeController is behaving like a singleton and avoiding singletons could be safer. For example, by default Play Framework uses Guice dependency injection which creates a new controller instance per request as long as it is not a #Singleton. One motivation is there is less state to worry about regarding concurrency protection as suggested by Nio's answer:
In general, it is probably best to not use #Singleton unless you have
a fair understanding of immutability and thread-safety. If you think
you have a use case for Singleton though just make sure you are
protecting any shared state.
When I create a Service with ServiceStack and can them easily test when just instanciating the class and running my unit tests.
But with this approach the validators don't get fires, because the runtime binds them and they are triggert before the serivce is called.
Do I have to make IntegrationTests with a running service ? Or is there a smarter way`?
We do both: unit test the actual validator and then also full integration test - so we can test out the whole filter pipeline.
Our unit tests look some thing like:
[Test]
public void Validate_POST_ValidRequest_ExpectIsValidTrue()
{
var request = new MyRequest { Id =99, Name = "fr", Venue = "My Venue", Age = 9 };
var validateRunner = new MyValidator();
var result = validateRunner.Validate(request, ruleSet: "POST");
Assert.That(result.IsValid, Is.True);
}
It depends on what actually you want to test.
You can make a test just for your validator class passing different DTO Request objects.
You can also make an integration test by inheriting your test fixture from TestBase.
I'm trying to consume a web service with the Web API client library. My problem is that the ReadAsAsync doesn't seem to want to fully deserailize the returned object when the submitting function uses a POST method.
If I get the response as a string and manually deserailize it works. (I get a apmsgMessage with all the fields populated)
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<apmsgMessage>(msg.Result);
I originally tried the code below which returns an apmsgMessage Object, but all the fields are null.
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsAsync<apmsgMessage>().Result;
return msg;
My question is why dosn't my orginal (the PostAsJsonAsync) return a apmsgMessage fully populated. Am I doing somethign wrong with the ReadAsAsync?
I just had the same issue, and in my case I solved it by removing the [Serializable] attribute from the class.
I don't know why this attribute conflicts with the deserialization process, but as soon as I took that out, the ReadAsAsync method worked as expected.
Can i start by saying i am new to programming and SoapUI(more like a week old). i apologies in advance for asking the question(s) i am about to ask.
Problem
basically, i am trying to automate webservice.
I need to create xml using Groovy in soapui and send it as part of a request body to a webservice(REST not SOAP) and do some assertion on the response received. i will be sending quite a few request, hence the reason to automate.
My proposed solution (which i am not sure about)
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.ContentType
import groovyx.net.http.Method
class XmlGenerator {
// I created a class i.e. called XmlGenerator with a
// static method called GetXML() which looks like this:
public static def GetXML()
{
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.GetDMessage() //creating the xml message
{
PrescribedItems
{
PrescribedMethod(xml,'Some Value','Some Value','Some Value')
PrescribedItem
{
PrescribedMethod(xml,'Some Value','Some Value','Some Value')
}
}
}
return writer
}
// This method creates the XML needed but then i need to
// pass the xml generated to a request boy; so i
//create another method within the same class:
static def postXML(String baseUrl, String path)
{
def RequestBody = XmlGenerator.GetXML() // i am not sure if this will work
try
{
def ret = null
def http = new HTTPBuilder(baseUrl)
http.request(Method.POST, ContentType.XML)
{
uri.path = path
body = RequestBody
}
}
catch (groovyx.net.http.HttpResponseException ex)
{
ex.printStackTrace()
return null
}
catch (java.net.ConnectException ex)
{
ex.printStackTrace()
return null
}
}
}
Summary
A class called XmlGenerator() with 2 methods; GetXML() (used to generate XML ) and postXML() (Used to send XML generated by GetXML() to the Webservice.)
Questions
How can i make sure that this 2 methods ( GetXML() and postXML() ) are used by other request messages i.e. do i need to import the groovy scripte.g. do i do an import ... GroovyScriptName , if yes, please how?
How can i create create the xml and run the request in subsequent request messages. For instance;
do i do this; XmlGenerator() gen = new XmlGenerator(), then do gen.GetXML() and gen.postXML() to create and run the request. Also, what role can testRunner play in all this
Running the code currently throws up HTTPBuilder, ContentType , Method can not be resolved even though i have imported them in the script (see above)
Finally, what role can property play in building this framework? bearing in mind that the each request will be independent from the other request i.e. nothing is been passed around from one request to the other during test execution
You can specify the REST request you are testing using standard soapui functionality, as outlined here:
http://www.soapui.org/REST-Testing/getting-started.html
Follow the steps in the above page to create a:
New REST Service
New REST Resource
New REST Method
Then you can add a REST Test Step to your Test Case that invokes that request.
You can then insert a Groovy Test Step before the REST Test Step to build your xml body; here's a simple example of building a XML string:
import groovy.xml.MarkupBuilder
context.writer = new StringWriter()
def xml = new MarkupBuilder(context.writer)
xml.books() {
book(name:'blue ocean') {
format ('paperback')
year ('2010')
}
book(name:'quicksilver') {
format ('hardback')
year ('2011')
}
}
Note that the XML is assigned to a context variable (context.writer). This makes it available for use in subsequent steps within the scope of the Test Case for the duration of the test run.
Then, insert the following code into the body of your REST Test Step:
${=context.writer}
Finally, you have the option of adding Assertions within the REST Test Step; here's some information on that:
http://www.soapui.org/Functional-Testing/getting-started-with-assertions.html