Kotlin sealed class and type inference - unit-testing

im using a sealed class to report back success or error to client code:
sealed class Result<out T : Any> {
data class Success<out T : Any>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
}
But im stuck getting even the simplest unit test to compile using it:
val error = Result.Error(IOException("message"))
assertThat(error, instanceOf(Result.Error::class.java))
I get the message : Type Inference failed. Not enough information to infer parameter T in fun instanceOf(type : Class<*>) : Matcher!
Looks like im missing something important in Kotlin.
Thanks for helping me out!

there is no problem with your code for me.
import org.hamcrest.CoreMatchers.instanceOf
import org.junit.Test
import org.junit.Assert.*
import java.io.IOException
class ExampleUnitTest {
#Test
fun test1() {
val error = Result.Error(IOException("message"))
assertTrue(error is Result.Error)
}
#Test
fun test2() {
val error = Result.Error(IOException("message"))
assertThat(error , instanceOf(Result.Error::class.java))
}
sealed class Result<out T : Any> {
data class Success<out T : Any>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
}
}
Also, I'll suggest you to use the keyword is to check if your class is an instance of something in kotlin (like in test1)

Looks like i was looking in the false API. As im mostly using assertj.
Below code is clean and fluent to read
assertThat(result).isInstanceOf(Result.Error::class.java)

To avoid ::class I prefer this.
assertThat(result is Result.Error).isTrue()

Related

could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[class]

i am new to akka http and i am having difficulty in marshalling and un-marshalling of my case class
here is my code
case class Event(uuid:String)
//main class
class demo {
val route: Route =
post {
path("create-event") {
entity(as[Event]) { event =>
complete("event created")
}
}
}
}
}
i am getting a compile time error on this line
entity(as[Event]) { event =>
could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[models.event.Event]
There is an easy way to solve this. akka-http-jackson has an implementation for Request Unmarshaller.
sbt add lib:
"de.heikoseeberger" %% "akka-http-jackson" % "1.27.0"
and then in your code
import de.heikoseeberger.akkahttpjackson.JacksonSupport._
By default, Akka-Http uses spray to marshal and unmarshal json and the error is because no implicit converter which is used for conversion is defined.
import spray.json.DefaultJsonProtocol
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json._
trait EventProtocol extends DefaultJsonProtocol {
implicit val eventJsonFormat = jsonFormat1(Event)
}
class demo extends SprayJsonSupport with EventProtocol {
// your code
}
The detailed steps are provided in akka-http documentation
Hope it helps!!

Dependency Injection with Moq and AutoMoq (AutoFixture) w/ xUnit

I'm writing this because I've tried for a bit to figure this out myself with no luck. Every example I can find for whatever reason seems to suggest that this just works out of the box but whenever I try to do the same, I always get errors. Basically, I have a controller with two properties that are injected via. DI, let's say
public class SomeController
{
private ISomeInterface _i;
private MyConfig _c;
public SomeController(ISomeInterface i, MyConfigContext cxt) // Where cxt is Type of DbContext
{
_i = i;
_c = cxt.Configs.FirstOrDefault();
}
public OkResult PostModel(SomeModel c)
{
// Do things
return Ok();
}
}
And in my tests using xUnit, Moq & AutoFixture I'm trying to avoid having to manually instantiate dependencies B and C:
public class SomeControllerTests
{
private MyDbContext _cxt;
private Fixture _fixture;
public SomeControllerTests()
{
_cxt = GetCxt() // GetCxt() just returns a context instance, nothing special
_fixture = new Fixture();
_fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
_fixture.Customizations.Add(
new TypeRelay(
typeof(ISomeInterface),
typeof(SomeConcreteClass)
)
);
}
[Fact, AutoData]
public void PostStatus_ReturnsOk_GivenValidRequest()
{
SomeController c = _fixture.Create<SomeController>();
SomeModel m = _fixture.Create<SomeModel>();
var result = c.PostModel(m);
Asset.IsType<OkResult>(result);
}
}
With the above I am getting a NotImplementedException when I run the tests and it won't tell me what exactly is not being implemented so I have no way of knowing what the issue is. I must be missing something in the docs. I want to use AutoFixture to make my tests more durable but so far it has been a pain trying to use it. I really don't want to have to mock/stub my entire app manually just to run a test. I would ideally like to use the syntax shown in the AutoFixture docs where you put your test-relevant instances in the params of the test and they are created for you but I haven't had any luck with it, like...
[Theory, AutoData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}
Thanks for Reading (:
Try to add next attribute and use it instead of AutoData.
using AutoFixture.AutoMoq;
using AutoFixture.Xunit2;
namespace Cats
{
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
}
[Theory, AutoMoqData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}

Spock unit testing assert log calls and see output

I am using spock to test Java Spring Boot code. It gets a logback logger over the lombok #Slf4j annotation.
Dummy class with log call
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
#Slf4j
#Component
public class Clazz {
public void method() {
// ... code
log.warn("message", new RuntimeException());
}
}
The Spock Spec
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.Logger
import spock.lang.Specification
#Slf4j
class LogSpec extends Specification {
Clazz clazz = new Clazz()
private Logger logger = Mock(Logger.class)
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning ia logged"() {
given: "expected message"
when: "when calling the method"
clazz.method()
then: "a warning is logged"
1 * logger.warn(_, _) >> {
msg, ex -> log.warn(msg, ex)
}
}
}
Helper to switch the real with the mock logger taken from this answer.
import org.junit.rules.ExternalResource
import org.slf4j.Logger
import java.lang.reflect.Field
import java.lang.reflect.Modifier
/**
* Helper to exchange loggers set by lombok with mock logger
*
* allows to assert log action.
*
* Undos change after test to keep normal logging in other tests.
*
* code from this answer answer
*/
class ReplaceSlf4jLogger extends ExternalResource {
Field logField
Logger logger
Logger originalLogger
ReplaceSlf4jLogger(Class logClass, Logger logger) {
logField = logClass.getDeclaredField("log")
this.logger = logger
}
#Override
protected void before() throws Throwable {
logField.accessible = true
Field modifiersField = Field.getDeclaredField("modifiers")
modifiersField.accessible = true
modifiersField.setInt(logField, logField.getModifiers() & ~Modifier.FINAL)
originalLogger = (Logger) logField.get(null)
logField.set(null, logger)
}
#Override
protected void after() {
logField.set(null, originalLogger)
}
}
I would like to test log calls, but still see the log message.
I am using the solution from this answer, it works for the assertion but I don't see the log because it is a mock call.
I came up with this solution, which does a the call with the logger of the groovy spec.
1 * logger.warn(_ , _) >> {
msg, ex -> log.warn(msg, ex)
}
But I find it verbose, any idea how I could create a helper function for it. I am not very familiar with functional groovy and moving this code into a function is not working.
I also tried a Spy instead of a Mock but that gets me an error because the logger class is final.
import ch.qos.logback.classic.Logger
private Logger logger = Spy(Logger.class)
>> org.spockframework.mock.CannotCreateMockException: Cannot create mock
for class ch.qos.logback.classic.Logger because Java mocks cannot mock final classes.
If the code under test is written in Groovy, use a Groovy mock.
Logger class at runtime
package ch.qos.logback.classic;
public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
Thanks
Actually in your MCVE you expect the warn(_, _) method to be called with two parameters, but you are not logging like that in Clazz, so either you have to change Clazz to also log an exception or change the test to expect a method call with one parameter. I am doing the latter here.
As for your problem, the solution is to not use a mock but a spy. You need to tell Spock which exact class you want to spy on, though. This is because you cannot spy on an interface type, of course. I have chosen a SimpleLogger (change to whatever you use in your application).
package de.scrum_master.stackoverflow
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.impl.SimpleLogger
import spock.lang.Specification
#Slf4j
class LombokSlf4jLogTest extends Specification {
SimpleLogger logger = Spy(constructorArgs: ["LombokSlf4jLogTest"])
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning is logged"() {
when: "when calling the method"
new Clazz().method()
then: "a warning is logged"
1 * logger.warn(_)
}
}
Update: For what it is worth, here is a version which also works with LogBack-Classic instead of Log4J-Simple on the classpath. Instead of directly spying on the final class, let's just spy on a Groovy #Delegate:
Please also note that I changed to *_ in the test so as to accommodate to warn calls with an arbitrary number of arguments.
package de.scrum_master.stackoverflow
import groovy.util.logging.Slf4j
import org.junit.Rule
import org.slf4j.Logger
import spock.lang.Specification
#Slf4j
class LombokSlf4jLogTest extends Specification {
def logger = Spy(new LoggerDelegate(originalLogger: log))
#Rule
ReplaceSlf4jLogger replaceSlf4jLogger = new ReplaceSlf4jLogger(Clazz, logger)
def "warning is logged"() {
when: "when calling the method"
new Clazz().method()
then: "a warning is logged"
1 * logger.warn(*_)
true
}
static class LoggerDelegate {
#Delegate Logger originalLogger
}
}
Update 2020-01-23: I just found this one again and noticed that I forgot to explain why the #Delegate solution works: because a Groovy delegate automatically implements all interfaces which the class of the delegate instance also implements by default. In this case the logger field is declared as Logger which is an interface type. This is also why e.g. Log4J or Logback instances can be used based on the configuration. The trick of mocking or spying on a final class type not implementing an interface or used explicitly with its class name would not work in that case because the delegating class would not (and could not) be a subclass of the final class type and thus could not be injected instead of the delegate.
Update 2020-04-14: I did not mention before that if you don't want to spy on a real logger but simply use a dummy you can check interactions on, just use a regular Spock mock on the org.slf4j.Logger interface: def logger = Mock(Logger) That is actually the simplest solution and you don't clutter your test log with exception stack traces and other log output. I was so focused on helping the OP with his spy solution that I did not mention this before.
These is one more "creative" approach for this kind of issue I would like to share.
Instead of mocking the logger you can create an "artificial" appender, add it programmatically to the logger in the class under-test.
The appender will keep track of the logged messages and during the verification phase you will get those logged message and verify
You'll end up with something like this (pseudo code just to show the idea):
class MsgTrackingAppender implements Appender { // Appender of your logging system
private List<LogEvent> events = new ArrayList<>();
public void doAppend(LogEvent evt) {
events.add(evt);
}
public List<LogEvent> getEvents() {
return events;
}
}
// now in test you can do:
class LogSpec extends Specification {
def "test me"() {
given:
Clazz underTest = Clazz()
MsgTrackingAppender appender = new MsgTrackingAppender()
LogFactory.getLogger(Clazz.class).addAppender(appender)
when:
underTest.method()
then:
appender.events.size == 1
appender.events[0].level == Level.WARN
appender.events[0].message == ... // verify whatever you want on the messages
}
}
IMO this approach is easier to use than extensive mocking but its a matter of taste of course.

How do I test a class using JUnit 4 that extends an abstract class?

I am trying to write a unit test for a java class that is extending an abstract class? The java class looks sort of like:
public class XYZFilter extends XYZDataFilter{
#Override
protected boolean filterItem(Model d, String sector) {
//method code
return true;
}
}
The junit test class looks like:
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class XYZFilterTest {
Model m = new Model();
String sector = "SECTOR";
#Test
public void testFilterItem() throws Exception {
System.out.println("\nTest filterItem method...");
XYZFilter f = new XYZFilter();
assertTrue(f.filterItem(m, sector));
}
}
So I'm having a problem with the abstract DataFilter which is extended by the Filter class, as well as the Model class. I believe I need to mock these objects using JMockit but I am having a lot of trouble figuring out how to do this. Any advice is appreciated.
The answer is I needed to have the libraries included, JMockit doesn't handle objects in that way.

Bug in Mockito with Grails/Groovy

I am using Mockito 1.9 with Grails 1.3.7 and I have a strange bug.
The following test case in java works:
import static org.mockito.Mockito.*;
public class MockitoTests extends TestCase {
#Test
public void testSomeVoidMethod(){
TestClass spy = spy(new TestClass());
doNothing().when(spy).someVoidMethod();
}
public static class TestClass {
public void someVoidMethod(){
}
}
}
This test in groovy does not work:
import static org.mockito.Mockito.*
public class MockitoTests extends TestCase {
public void testSomeVoidMethod() {
def testClassMock = spy(new TestClass())
doNothing().when(testClassMock).someVoidMethod()
}
}
public class TestClass{
public void someVoidMethod(){
}
}
This is the error message:
only void methods can doNothing()!
Example of correct use of doNothing():
doNothing().
doThrow(new RuntimeException())
.when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
org.mockito.exceptions.base.MockitoException:
Only void methods can doNothing()!
Example of correct use of doNothing():
doNothing().
doThrow(new RuntimeException())
.when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:129)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:146)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
Does anymone observed the same error?
The problem is Groovy is intercepting your method call before it reaches someVoidMethod. The method actually being called is getMetaClass which is not a void method.
You can verify this is happening by replacing:
doNothing().when(testClassMock).someVoidMethod()
with:
doReturn(testClassMock.getMetaClass()).when(testClassMock).someVoidMethod()
I'm not sure you will be able to get around this issue using stock Mockito and Groovy.