Very new to Rust, and I've run into an issue with trying to get doc comment tests working.
I'm hoping to have a module that isn't public, but has some tests in the doc comments.
src/lib.rs:
pub mod module;
fn foo() {
println!("{}", module::get_hello());
}
src/module.rs:
/// Gets a nice Hello message
///
/// ```
/// use test_namespace::module::get_hello;
/// let msg = get_hello();
/// assert_eq!(msg, "Hello, World!".to_string());
/// ```
pub fn get_hello() -> String {
"Hello, World!".to_string()
}
The only way I've been able to get this test working is if I have pub mod module;. I feel like there should be some way of running this test without the use test_namespace::module::get_hello; at all since it's a test in the same module. Hoping to get some clarification.
Related
I recently updated to actix web 4, I had some tests that used the actix-web test module that stopped working as expected in the process. I'm sure it's something simple but I'm having trouble figuring out what changed. Here is a minimal example of the issue:
use actix_web::{test, web, App, HttpResponse, HttpRequest};
#[actix_rt::test]
async fn says_hello() {
let req = test::TestRequest::get().uri("/index.html").to_request();
let mut server =
test::init_service(App::new().service(web::scope("/").route("index.html", web::get().to(|_req: HttpRequest| async {
println!("Hello?");
HttpResponse::Ok()
})))).await;
let _resp = test::call_and_read_body(&mut server, req).await;
}
running this test I would expect to see "Hello?" output to my console, however, the request handler function I have defined at "/index.html" doesn't seem to be called and I receive no output.
To be clear, the tests are more complicated and have assertions etc, this is just a working example of the main issue I am trying to resolve
actix-web = { version = "4.1.0", default-features = false }
note:
if I change all paths to the root path it will call the handler, I.E.
let req = test::TestRequest::get().uri("/").to_request();
let mut server =
test::init_service(App::new().service(web::scope("/").route("/", web::get().to(|_req: HttpRequest| async {
println!("Hello?");
HttpResponse::Ok()
})))).await;
let _resp = test::call_and_read_body(&mut server, req).await;
// prints "Hello?" to the console
However no other route combination I have tried calls the request handler.
Rust tests capture the output and only output them for failed tests.
If you want to show output on all tests you have to tell them to do so with either testbinary --nocapture or cargo test -- --nocapture.
I was able to make things work by changing the path in the scope to an empty string
let req = test::TestRequest::get().uri("/index.html").to_request();
let mut server =
test::init_service(App::new().service(web::scope("").route("index.html", web::get().to(|_req: HttpRequest| async {
println!("Hello?");
HttpResponse::Ok()
})))).await;
let _resp = test::call_and_read_body(&mut server, req).await;
// prints "Hello?"
Later Edit
I ended up to have my api service methods suspended and refactor my code as suggested by #LordRaydenMK.
The reason for using the library ru.gildor.coroutines:kotlin-coroutines-retrofit it the first place was out of pure convenience AND it was before retrofit released the version which would support for coroutines.
Original Question
I have been trying for a couple of days to mock the API calls with no success. I'm using the following libraries:
retrofit - i think we are all familiar with it
ru.gildor.coroutines:kotlin-coroutines-retrofit - for a couple of useful coroutine extensions
io.mockk:mockk - for mocking
It is a simple case of mocking the API response
interface ApiService {
#GET
fun getMyData(#Header("x-value") myValue: String): Call<String>
}
class Usecase(api: ApiService) {
suspend fun execute() {
val result = api.getMyData(value: String).awaitResult()
// do smth with that result for now just return it
return (result as Result.Ok).value
}
}
class UseCaseTest {
private val api = mockk<ApiService>()
#Test
fun testApiCall() {
coEvery { api.getMyData(any()) } returns CallTest.buildSuccess("you did it!")
val result = useCase.execute()
assertEquals(result, "you did it!")
}
}
In the example above the test hangs on the awaitResult extension method.
What i have tried so far with no luck:
mockkStatic(ru.gildor.coroutines.retrofit.CallAwait) but with no success
mockk Call<String> and do a coEvery { mockedCall.awaitResult() } returns ....
I'm sure it's something simple that I'm missing and a pair of fresh eyes will spot it from a mile away.
First thing:
getMyData is NOT a suspend function so probably you should NOT be using coEvery when mocking it (tho I'm not a Mockk user).
That being said, Retrofit does support suspend functions natively, so you could do:
interface ApiService {
#GET
suspend fun getMyData(#Header("x-value") myValue: String): String
}
that means no need for awaitResult in your use case. In this scenario you do need coEvery when mocking it.
How can I get JenkinsPipelineUnit to intercept both text() and string() param calls? I have code that triggers a build with a few params. I want to write a nice unit test to check that it does what it should. However, the string() calls are not intercepted so I cannot test them. I can test the text() call.
Yes, it is possible to write unit tests for Jenkins pipeline code vs testing via jenkins production jobs. This project + shared libraries makes jenkins into a much better tool.
Any ideas on how I could do this? I looked in the JenkinsPipelineUnit project but didn't find an example that fit and couldn't figure out where to look in the runtime objects.
I do see that the project's BasePipelineTest.groovy links string to its stringInterceptor which seems to just eat it the string. Maybe, I can unregister theirs...
Example
def triggeringParams = [:]
....
for (def param in ['text', 'string']) {
helper.registerAllowedMethod(param, [LinkedHashMap],
{ LinkedHashMap data ->
triggeringParams << data
}
)
}
thisScript = helper.loadScript('''
package resources
return this''')
def params = []
params << thisScript.text(name: 'MULTILINE_PARAM', value: '\nline1\nline2')
params << thisScript.string(name: 'STRING_PARAM', value: 'a string')
thisScript.build(job: 'myJob', parameters: params)
println triggeringParams
Results
[
[name:JOB_PROPERTIES, value:
line1
line2]
]
Wrong type was the problem. The project's BasePipelineTest.groovy links string to its stringInterceptor which seems to just eat it the string and uses register Map not LinkedHashMap. So, the first is found before mine and boom, the string doesn't show in my collector.
If I modify my code to use the more generic map it works
void addParameterHelpers() {
for (def param in ['text', 'string']) {
helper.registerAllowedMethod(param, [Map],
{ LinkedHashMap data ->
triggeringParams << data
}
)
}
}
I have a problem that should be relatively straight-forward but I find myself going into a deep rabbit hole
I would like to Unit Test my call to Elasticsearch - with the search request including the aggs. What is a good way to go about mocking the response?
Elasticsearch RestHighLevelClient is very complex ... one has to deal with the complex web of XContentType/XContentType parser call chains
Is there a simple way to mock the call? I have sample JSON responses that one would receive if we called ES from Kibana Devtools
private fun searchResponseFromContent(content: String): SearchResponse {
val xContentType = XContentType.JSON
val parser = xContentType.xContent().createParser(
NamedXContentRegistry.EMPTY, // this would not handle aggrgations
null,
content
)
return SearchResponse.fromXContent(parser)
}
Generally speaking do people just not test Elasticsearch calls in their unit test? There doesn't seem to be any good solutions to mock calls to ES
The answer is just simplify what RestHighLevelClient is doing internally:
private fun searchResponseFromContent(content: String): SearchResponse {
val xContentType = XContentType.JSON
val parser = xContentType.xContent().createParser(
NamedXContentRegistry(namedXContentRegistry()),
null,
content
)
return SearchResponse.fromXContent(parser)
}
private fun namedXContentRegistry(): List<NamedXContentRegistry.Entry> {
// add as needed from RestHighLevelClient:1748 on version 7.3.2
// static List<NamedXContentRegistry.Entry> getDefaultNamedXContents()
return listOf(
NamedXContentRegistry.Entry(Aggregation::class.java, ParseField(HistogramAggregationBuilder.NAME), ContextParser { p, c ->
ParsedHistogram.fromXContent(p, c as String)
})
)
}
I am working with grails and writing tests using Spock framework.
I am trying to figure out what is the correct section (given, where, then, setup ...) in the test to put mock code.
For example, is the following correct?
void "test Something"() {
given:
//build mock and add demand statements...
when:
//Call method
}
I tend to put my demands in the then section unless I have complex mocks in which case I put them in the given, but they will work both places.
void "test Something"() {
given:
def myService = Mock(MyService)
mainThing.myService = myService
when:
mainThing.doCall()
then:
1 * myService.call() >> 'value'
}