I have some static method:
class WebUtils {
static httpPostRequest(String url, Map data, Map headers) {
//some code here
}
}
And service:
class ChatService {
void sendMessage(String text) {
//some preparing code
WebUtils.httpPostRequest(url, data, headers)
}
}
Now I want to check invocation of static method in the service by unit-test. Somehow like this:
void "test sending message"() {
given:
String text = 'Test'
def mockedWebUtils = Mock(WebUtils)
when:
service.sendMessage(message)
then:
1*mockedWebUtils.httpPostRequest(_, [text: message], _)
}
But code above is not working. Is there legal way?
Try something like:
void "test sending message"() {
given:
WebUtils.metaClass.static.httpPostRequest = { String url, Map data, Map headers ->
return 'done' // you can do what you want here, just returning a string as example
}
when:
service.sendMessage( 'Test' )
then:
1
// test for something your method has done
}
The correct way is using GroovyMock instead Mock:
void "test sending message"() {
given:
String text = 'Test'
GroovyMock(global:true, WebUtils)
when:
service.sendMessage(text)
then:
1*WebUtils.httpPostRequest(_, [text: text], _)
}
I've found here:http://spockframework.org/spock/docs/1.3-RC1/interaction_based_testing.html#_mocking_static_methods
Related
I am looking for a way in the Dart programming language to redirect the
output from stdout, into a "Something", that I can call .toString() on, and get
anything printed on stdout as String. This is useful for unit tests.
Currently I wrap stdout in my Display class, and store the text for one call and verify that stdout's write is
used. See also my side note below, how it can be done in Java.
import 'dart:io';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
class Display {
IOSink output;
String lastTextPrinted;
Display(IOSink output) {
this.output = output;
}
void myPrint(String text) {
lastTextPrinted = text;
output.write(text);
}
}
main() {
test('prints hello world', () {
Display display = new Display(stdout);
display.myPrint("Hello world!");
expect("Hello world!", display.lastTextPrinted);
});
test('myPrint calls ioSinks write', () {
MockIOSink ioSink = new MockIOSink();
Display display = Display(ioSink);
display.myPrint("Hello world!");
verify(ioSink.write("Hello world!"));
});
}
class MockIOSink extends Mock implements IOSink {}
Sidenote: In Java with JUnit 4 I used something similar to this:
There System.out is a PrintStream and I can assign my own Stream to it, for instance ByteArrayOutPutStream.
The latter has a .toString method I can call to verify its content against.
#Test
public void testMyMessageToDisplay() throws Exception
{
ByteArrayOutputStream canvas = new ByteArrayOutputStream();
System.setOut(new PrintStream(canvas);
new Display().displayMyMessage("Hello world!");
Assert.assertEquals("Hello World!", canvas.toString("UTF-8"));
}
public static class Display {
public void displayMyMessage(String myMessage) {
System.out.println(myMessage);
}
}
Look at https://pub.dartlang.org/packages/test_process – it gives a lot of nice methods for verifying the output of a process
See the example in the readme:
import 'package:test/test.dart';
import 'package:test_process/test_process.dart';
void main() {
test("pub get gets dependencies", () async {
var process = await TestProcess.start("pub", ["get"]);
// Each stream matcher will consume as many lines as it matches from a
// StreamQueue, and no more, so it's safe to use them in sequence.
await expectLater(process.stdout, emits("Resolving dependencies..."));
// The emitsThrough matcher matches and consumes any number of lines, as
// long as they end with one matching the argument.
await expectLater(process.stdout, emitsThrough("Got dependencies!"));
await process.shouldExit(0);
});
}
Given the following setup:
class MockingFilters {
def filters = {
all(controller:"simple", action:"list") {
before = {
log.info "This needs asserting"
return false
}
}
}
}
Is there a way to assert that the log.info has fired? I am unsure how to get a handle on the Filter, and thus be able to interaction test the log object.
void "test list action is filtered"() {
when:
withFilters(action:"list") {
// Important bit
// Not sure how to get a handle to the filter
1 * log.info("This needs asserting")
controller.list()
}
then:
// Whatever here
}
There are also other objects on the Filter that I would like to test, but this example should be reflective of those too.
I am trying to use a library for showing Flash Messages https://github.com/elpete/flashmessage But I am having trouble getting it working correctly. The documentation isn't that great and I am new to ColdFusion. I want to have the ability to have persistent error messages across pages. Specifically during checkout so when the user needs to go back or a validation error occurs the message will appear. According to the documentation:
The FlashMessage.cfc needs three parameters to work:
A reference to your flash storage object. This object will need
get(key) and put(key, value) methods. A config object with the
following properties: A unique flashKey name to avoid naming
conflicts. A reference to your containerTemplatePath. This is the view
that surrounds each of the individual messages. It will have
references to a flashMessages array and your messageTemplatePath. A
reference to your messageTemplatePath. This is the view that
represents a single message in FlashMessage. It will have a reference
to a single flash message. The name is chosen by you in your container
template. Create your object with your two parameters and then use it
as normal.
I am getting the error
the function getMessages has an invalid return value , can't cast null value to value of type [array]
I had this script somewhat working at one point but it seems very finicky. I believe it is my implementation of it. I am hoping someone here can help me figure out where I went wrong. Or give me some pointers because I am not sure I am even implementing it correctly.
This is What I have in my testing script:
<cfscript>
alertStorage = createObject("component", 'alert');
config = {
flashKey = "myCustomFlashKey",
containerTemplatePath = "/flashmessage/views/_templates/FlashMessageContainer.cfm",
messageTemplatePath = "/flashmessage/views/_templates/FlashMessage.cfm"
};
flash = new flashmessage.models.FlashMessage(alertStorage, config);
flash.message('blah');
flash.danger('boom');
</cfscript>
And inside of alert.cfc I have:
component {
public any function get(key) {
for(var i = 1; i < ArrayLen(session[key]); i++) {
return session[key][i];
}
}
public any function put(key, value) {
ArrayAppend(session.myCustomFlashKey, value);
return true;
}
public any function exists() {
if(structKeyExists(session,"myCustomFlashKey")) {
return true;
} else {
session.myCustomFlashKey = ArrayNew();
return false;
}
}
}
The Flash Message Component looks like this:
component name="FlashMessage" singleton {
/**
* #flashStorage.inject coldbox:flash
* #config.inject coldbox:setting:flashmessage
*/
public FlashMessage function init(any flashStorage, any config) {
instance.flashKey = arguments.config.flashKey;
singleton.flashStorage = arguments.flashStorage;
instance.containerTemplatePath = arguments.config.containerTemplatePath;
instance.messageTemplatePath = arguments.config.messageTemplatePath;
// Initialize our flash messages to an empty array if it hasn't ever been created
if (! singleton.flashStorage.exists(instance.flashKey)) {
setMessages([]);
}
return this;
}
public void function message(required string text, string type = "default") {
appendMessage({ message: arguments.text, type = arguments.type });
}
public any function onMissingMethod(required string methodName, required struct methodArgs) {
message(methodArgs[1], methodName);
}
public any function render() {
var flashMessages = getMessages();
var flashMessageTemplatePath = instance.messageTemplatePath;
savecontent variable="messagesHTML" {
include "#instance.containerTemplatePath#";
}
setMessages([]);
return messagesHTML;
}
public array function getMessages() {
return singleton.flashStorage.get(instance.flashKey, []);
}
private void function setMessages(required array messages) {
singleton.flashStorage.put(
name = instance.flashKey,
value = arguments.messages
);
}
private void function appendMessage(required struct message) {
var currentMessages = getMessages();
ArrayAppend(currentMessages, arguments.message);
setMessages(currentMessages);
}
}
I'm writing a unit test which tests the scenario where a body is sent in the request which is a plain string, i.e. not parseable as JSON.
In this test, I'm setting the HttpRequestMessage something like this:
var ojectContent = new ObjectContent(typeof(string)
, "aaaaa"
, new JsonMediaTypeFormatter());
httpRequestMessage.Content = objectContent;
The problem is, when I debug the code, the request body has been set to "aaaaa" (note the additional quotes) which is enough to cause the deserialisation code to treat the request body differently, meaning I can't test what I mean to test. I need the request body to be aaaaa.
Can anyone advise how I can set up the test so that the request body does not contain these quotes?
Edit: I have also tried new ObjectContent(typeof(object)... and it gives the same result.
Another way is to bypass the MediaTypeFormatter by using StringContent instead of ObjectContent:
var content = new StringContent("aaaaa");
httpRequestMessage.Content = content;
Okay, so I needed to create a media type formatter that didn't interfere with the input in any way. I used this:
private class DoNothingTypeFormatter : MediaTypeFormatter
{
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
if (type == typeof(string))
{
return true;
}
return false;
}
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, HttpContent content, TransportContext transportContext)
{
var myString = value as string;
if (myString == null)
{
throw new Exception("Everything is supposed to be a string here.");
}
var length = myString.Length;
var bytes = System.Text.Encoding.UTF8.GetBytes(myString);
return Task.Factory.StartNew(() => writeStream.Write(bytes, 0, length));
}
}
Then, when I want to generate the body of the `HttpRequestMessage', I do so like this:
objectContent = new ObjectContent(typeof(string)
, "not json"
, new DoNothingTypeFormatter());
I have the following functions in a controller
def render201 = {
render(status:201)
}
def render202 = {
response.setStatus(202)
}
def render203 = {
response.setStatus(203)
render(status:203)
}
def render204 = {
response.setStatus(204)
render(status:205)
}
And I have the following tests
void test201() {
controller.render201()
assertEquals(201, controller.response.status)
}
void test202() {
controller.render202()
assertEquals(202, controller.response.status)
}
void test203() {
controller.render203()
assertEquals(203, controller.response.status)
}
void test204() {
controller.render204()
assertEquals(204, controller.response.status)
}
test201 fails with this message
junit.framework.AssertionFailedError: expected:<201> but was:<200>
For some reason, if you don't explicitly set the response status, render will always return 200 when being run from a unit test.
Additionally, if I were to actually call these from a browser, render202 would return an error, but render201 and render203 would work just fine. I don't know what render204 would do.
What's going on here? Is this a bug in Grails?
Try something like this :
assertEquals(201, controller.renderArgs.status)
It worked for me.
If you want to understand the inside of mockController, look at :
https://svn.codehaus.org/grails/trunk/grails/src/groovy/grails/test/MockUtils.groovy
clazz.metaClass.getForwardArgs = {-> fwdArgs}
clazz.metaClass.getRedirectArgs ={-> redArgs}
clazz.metaClass.getRenderArgs ={-> renArgs}
clazz.metaClass.forward = {Map map -> forwardArgs.putAll(map)}
clazz.metaClass.redirect = {Map map -> redirectArgs.putAll(map)}
clazz.metaClass.render = {String text -> delegate.response.writer << text}
clazz.metaClass.render = {Converter arg -> delegate.response.writer << arg.toString()}
expected:<201> but was:<200> means you try to request operation which is returning some response. If you want to test 201 need to void method.