Add optional message parameter to assertEquals - unit-testing

Disclaimer: I'm totally new to Haxe, but I have experience in many other languages.
I have tests similar to the following:
function doTest(type:SomethingMagic, tests:Array<Array<Int>>) {
for (t in tests) {
var res = DoSomeMagicalWork(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
assertEquals(type, res.type);
}
}
The problem with this is that the unit test framework, when run on many different arrays, doesn't give me the correct line for which the test failed. In other words, if I'm running this method with a bunch of arrays, like:
doTest(SOME_MAGIC_TYPE,
[[0, 0, 0, 1625, 0, 35, 0, 0, 0, 0, 0],
...
]);
and one of these lines fails, it doesn't tell me which line failed. Now, I know that I could probably restructure these tests to be a bit more intuitive anyway, but this was written by someone else, and I don't have the ability to change each of these at the moment.
What I'd like to do is the following:
function doTest(type:SomethingMagic, tests:Array<Array<Int>>) {
var number = 0;
for (t in tests) {
var res = DoSomeMagicalWork(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
assertEquals(type, res.type, "Test #" + number + " for type " + type);
number++;
}
}
So, basically, I'd like to be able to pass in some extra messaging information to the assertEquals function, similar to what one can do in other unit testing frameworks. Then, upon failure, it would output the standard assertion message, possibly appended by the additional message I sent as a parameter to the function. Originally, I thought it was as simple as sub-classing haxe.TestCase, but that doesn't appear to be quite as simple as I thought, due to the way Haxe interprets types (apparently).
Has anyone had success with something similar to this that could give me a recommendation on how to accomplish it?

If you want to only get the position of the error you can use haxe.PosInfos as the last argument of your doTest() function and pass that arguemnt to assertEquals() like this:
import haxe.unit.TestCase;
class Main {
static function main() {
var r = new haxe.unit.TestRunner();
r.add(new Test());
r.run();
}
}
class Test extends TestCase {
public function new() {
super();
}
public function testExample() {
doTest(1, 1);
doTest(1, 2);
doTest(3, 3);
}
function doTest(a:Int, b:Int, ?pos:haxe.PosInfos) {
assertEquals(a, b, pos);
}
}
Online example here
It will give you the position that called doTest() in the error:
Test::testExample() ERR: Main.hx:18(Test.testExample) - expected '1' but was '2'
Another option if you want to add a custom message is to catch the assertEquals() error and rethrow the currentTest with a custom error like this:
import haxe.unit.TestCase;
class Main {
static function main() {
var r = new haxe.unit.TestRunner();
r.add(new Test());
r.run();
}
}
class Test extends TestCase {
public function new() {
super();
}
public function testExample() {
doTest(1, 1, "Error on test 1");
doTest(1, 2, "Error on test 2");
doTest(3, 3, "Error on test 3");
}
function doTest(a:Int, b:Int, errorMsg:String, ?pos:haxe.PosInfos) {
try {
assertEquals(a, b, pos);
} catch(e:Dynamic) {
currentTest.error = errorMsg;
throw currentTest;
}
}
}
Online example here
Which will give you the following error:
Test::testExample() ERR: Main.hx:18(Test.testExample) - Error on test 2

You are effectively blending multiple tests into a single one. And Haxe cannot tell where your array element is defined (line number, etc)
What I suggest is to change the signature of doTest to accept Array<Int> instead of Array<Array<Int>> and call doTest multiple times instead of just once. Together with the suggestion from Justo, passing the pos object to assetEquals, you will get the position correctly.

Related

Kotlin Mockk : Unable to mock a list correctly

I am trying to verify that .shuffled() on a list is called, but get an error on running because of a prior .take(6) call on the list, and I cannot see a way around this.
Here is some code that gets the same error:
val mockList =
mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
val choiceList = spyk(listOf("String1", "String2")) { every { take(6) } returns mockList }
val tmp = choiceList.take(6)
val tmp2 = tmp.shuffled()
verify {mockList.shuffled())
On line 4, I get the following error:
class io.mockk.renamed.java.util.List$Subclass0 cannot be cast to class java.lang.Integer (io.mockk.renamed.java.util.List$Subclass0 is in unnamed module of loader 'app'; java.lang.Integer is in module java.base of loader 'bootstrap')
Attempting to go around by directly verifying on choiceList.take(6).shuffled() and combining the two tmp vals into one has had no success, as it gets true whether or not .shuffled() gets called. Also, switching from a spy to a mock for choiceList has also not worked.
Edit: Note, since this is a toy example, the take() is completely necessary, and cannot be removed, as it has real use in the actual code.
Interesting one!
I think in current implementation it is not possible. The easy answer would be "this test misses the declaration of wrapping static class" (as extension methods are just the same as java static methods for JVM). But if we add it...
#Test
fun test() {
mockkStatic("kotlin.reflect.jvm.internal.impl.utils.CollectionsKt")
val iterClass = mockkClass(Iterable::class)
val mockList = mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
with(iterClass) {
every { take(6) } returns mockList
val tmp = take(6)
val tmp2 = tmp.shuffled()
verify {
mockList.shuffled()
}
}
}
we have a Recursion detected in a lazy value under LockBasedStorageManager#1d2ad266 (DeserializationComponentsForJava.ModuleData) which is understandable - we just mocked the whole extensions package. And it is not possible to mock only one extension method leaving others intact. (source: https://github.com/mockk/mockk#extension-functions)
However, I'd do the following. Why not make our own extension functions which call the original and mock those?
It would go like this:
Main.kt:
package root
...
fun <T> Iterable<T>.take(n: Int): Iterable<T> {
val m = Iterable<T>::take
return m.call(this)
}
fun <T> Iterable<T>.shuffled(): Iterable<T> {
val m = Iterable<T>::shuffled
return m.call(this)
}
Test.kt:
package root
...
#Test
fun test() {
// note this changed
mockkStatic("root.MainKt")
val iterClass = mockkClass(Iterable::class)
val mockList = mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
with(iterClass) {
every { take(6) } returns mockList
val tmp = take(6)
val tmp2 = tmp.shuffled()
verify {
mockList.shuffled()
}
}
}
The only downside here I think is that it's reflection (duh!) So, this can possibly affect performance and has the requirement to have implementation(kotlin("reflect")) in the dependencies (to use call()). If it is not feasible I think there's no clean solution.
val mockList: List<String> = mockk(relaxed = true)
mockList.shuffled()
verify { mockList.shuffled() }
This works for me. The problem is that take of choiceList cannot be mocked somehow. Is that really necessary?

How can I prevent a method call when JUnit testing with Mockito?

For the life of me, I can't seem to figure out how to prevent the method I'm testing from calling a method in another class.
Here is my test class:
#ExtendWith(MockitoExtension.class)
class QueryHandlerTest {
#InjectMocks
QueryHandler queryHandler;
#Mock
ResponseBuilder responseBuilder;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
void TC5() {
doThrow(AddMessageResponseException.class).when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
assertThrows(AddMessageResponseException.class, ()-> queryHandler.addMessage("Hello",true));
}
}
Here is the method that I'm testing:
public void addMessage(String message, boolean lengthExceedsLimit) {
boolean messageAdded;
if (checkIfJarExists()) {
if (!lengthExceedsLimit) {
// attempt to add the message to the jar
messageAdded = addMessageQuery(new Message(event.getMessageAuthor().getIdAsString(), message));
} else {
messageAdded = false;
}
} else {
messageAdded = false;
}
responseBuilder.addMessageResponse(messageAdded, lengthExceedsLimit);
if (messageAdded) {
// check to see if the jar's message limit has been reached; if so, perform opening ceremony
if (checkMessageLimit()) {
responseBuilder.performOpeningEvent(currentJar);
deleteJarQuery(this.serverId);
}
}
}
And here is the method that it's calling:
public void addMessageResponse(boolean messageAdded, boolean lengthExceedsLimit){
if (lengthExceedsLimit) {
event.getChannel().sendMessage("I'm sorry, your message is too long. Please limit your message " +
"to 250 characters or less.");
} else if(messageAdded){
String nickname = getNickname();
event.getChannel().sendMessage("Thanks, " + nickname + "! Your message has " +
"been added to the jar!");
} else {
event.getChannel().sendMessage("Sorry, it looks like a jar has not been set up for your server. " +
"If you're a server admin, you can create a jar! " +
"Please use '!tiko help' to see a list of my commands.");
}
}
When I run the test, I get this output:
org.opentest4j.AssertionFailedError: Unexpected exception type thrown,
Expected :class com.tikoJar.exceptions.AddMessageResponseException
Actual :class java.lang.NullPointerException
<Click to see difference>
...
Caused by: java.lang.NullPointerException: Cannot invoke "org.javacord.api.entity.channel.TextChannel.sendMessage(String)" because the return value of "org.javacord.api.event.message.MessageCreateEvent.getChannel()" is null
at com.tikoJar.DTO.ResponseBuilder.addMessageResponse(ResponseBuilder.java:35)
at com.tikoJar.DTO.QueryHandler.addMessage(QueryHandler.java:74)
at com.tikoJar.DTO.QueryHandlerTest.lambda$TC5$0(QueryHandlerTest.java:68)
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:53)
... 73 more
As you can see, the method I'm testing is calling and running the addMessageResponse() method in the ResponseBuilder class, even though I specified in my test that a custom exception should be thrown when attempting to call that method.
I've also tried specifying:
doNothing().when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
... but the method still gets called and run. What can I do here?

Mockk AssertionError: Verification failed: call 1 of 1

///Here is my class
class State {
var state: Int = 10
}
open class Car {
var state:State = State()
fun changState(data: Int = 1) {
setState(data)
}
fun setState(data: Int = 0) {
state.state = data
}
}
/// Here is my Test
#Test
fun `test 1`() {
var mockCar = mockk<Car>()
every { mockCar.changState(any()) } just runs
every { mockCar.setState(any()) } just runs
mockCar.changState(10)
verify(exactly = 1) { mockCar.changState(any()) }
verify { mockCar.setState(any()) }
}
But it fails with this error
################################
java.lang.AssertionError: Verification failed: call 1 of 1: Car(#1).setState(any())) was not called.
Calls to same mock:
Car(#1).changState(10)
############################
You need to remove verify { mockCar.setState(any()) } - there is no way that this will ever be called, because you mocked
every { mockCar.changState(any()) } just runs
This means the stubbed method will do nothing, it just runs, so to speak.
I don't recommend writing tests that only test mocks, because it will lead to a bias that the code is fine when you just use outputs of what you think is correct behavior. Instead, write a separate unit test for Car.
For your use-case a mock is not the intended thing to use, you should be using a spy instead if you mix real method calls with mocked behavior.

Project Reactor: wait while broadcaster finish

There is a Broadcaster, that accepts strings and append them to a StringBuilder.
I want to test it.
I have to use Thread#sleep to wait, while the broadcaster finish processing of strings. I want to remove sleep.
I tried to use Control#debug() unsuccessfully.
public class BroadcasterUnitTest {
#Test
public void test() {
//prepare
Environment.initialize();
Broadcaster<String> sink = Broadcaster.create(Environment.newDispatcher()); //run broadcaster in separate thread (dispatcher)
StringBuilder sb = new StringBuilder();
sink
.observe(s -> sleep(100)) //long-time operation
.consume(sb::append);
//do
sink.onNext("a");
sink.onNext("b");
//assert
sleep(500);//wait while broadcaster finished (if comment this line then the test will fail)
assertEquals("ab", sb.toString());
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
I'm not familiar with Broadcaster (and it's probably deprecated since the question is old), but these 3 ways could be helpful in general:
When testing Project-Reactor's Fluxes and stuff, you're probably better of using their testing library made specially for this. Their reference and the Javadoc on that part are pretty good, and I'll just copy an example that speaks for itself here:
#Test
public void testAppendBoomError() {
Flux<String> source = Flux.just("foo", "bar");
StepVerifier.create(
appendBoomError(source))
.expectNext("foo")
.expectNext("bar")
.expectErrorMessage("boom")
.verify();
}
You could just block() by yourself on the Fluxes and Monos and then run checks. And note that if an error is emitted, this will result in an exception. But have a feeling you'll find yourself needing to write more code for some cases (e.g., checking the Flux has emitted 2 items X & Y then terminated with error) and you'd be then re-implementing StepVerifier.
#Test
public void testFluxOrMono() {
Flux<String> source = Flux.just(2, 3);
List<Integer> result = source
.flatMap(i -> multiplyBy2Async(i))
.collectList()
.block();
// run your asserts on the list. Reminder: the order may not be what you expect because of the `flatMap`
// Or with a Mono:
Integer resultOfMono = Mono.just(5)
.flatMap(i -> multiplyBy2Async(i))
.map(i -> i * 4)
.block();
// run your asserts on the integer
}
You could use the general solutions to async testing like CountDownLatch, but, again, wouldn't recommend and would give you trouble in some cases. For example, if you don't know the number of receivers in advance you'll need to use something else.
Per answer above, I found blockLast() helped.
#Test
public void MyTest()
{
Logs.Info("Start test");
/* 1 */
// Make a request
WebRequest wr1 = new WebRequest("1", "2", "3", "4");
String json1 = wr1.toJson(wr1);
Logs.Info("Flux");
Flux<String> responses = controller.getResponses(json1);
/* 2 */
Logs.Info("Responses in");
responses.subscribe(s -> mySub.myMethod(s)); // Test for strings is in myMethod
Logs.Info("Test thread sleeping");
Thread.sleep(2000);
/* 3 */
Logs.Info("Test thread blocking");
responses.blockLast();
Logs.Info("Finish test");
}

What are the best practices for unit testing properties with code in the setter?

I'm fairly new to unit testing and we are actually attempting to use it on a project. There is a property like this.
public TimeSpan CountDown
{
get
{
return _countDown;
}
set
{
long fraction = value.Ticks % 10000000;
value -= TimeSpan.FromTicks(fraction);
if(fraction > 5000000)
value += TimeSpan.FromSeconds(1);
if(_countDown != value)
{
_countDown = value;
NotifyChanged("CountDown");
}
}
}
My test looks like this.
[TestMethod]
public void CountDownTest_GetSet_PropChangedShouldFire()
{
ManualRafflePresenter target = new ManualRafflePresenter();
bool fired = false;
string name = null;
target.PropertyChanged += new PropertyChangedEventHandler((o, a) =>
{
fired = true;
name = a.PropertyName;
});
TimeSpan expected = new TimeSpan(0, 1, 25);
TimeSpan actual;
target.CountDown = expected;
actual = target.CountDown;
Assert.AreEqual(expected, actual);
Assert.IsTrue(fired);
Assert.AreEqual("CountDown", name);
}
The question is how do I test the code in the setter? Do I break it out into a method? If I do it would probably be private since no one else needs to use this. But they say not to test private methods. Do make a class if this is the only case? would two uses of this code make a class worthwhile? What is wrong with this code from a design standpoint. What is correct?
The way you've got is fine (call the setter and then check the get returns the expected value).
Make sure you choose a selection of test values that exercise all the paths in that setter. A single set/get test isn't sufficient coverage.