Trying to figure out how to pass some parameters to my custom implementation of TestWatcher in Junit5. The base class for all tests is set to #ExtendWith with the TestWatcher. Trying to keep it as simple as possible and I can't seem to find a straightforward answer on how to do this
I was struggling on a similar problem, basically I needed a global parameter (a separator string data) for the annotation #DisplayNameGenerator().
Because the lack of code examples of how you're trying to resolve this I'm gonna explain my approach of how to get a parameter provided by the user and see if it works for you,
I created a interface with the return of the String value that is my custom parameter that I wanted to get from the user,
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#API(status = EXPERIMENTAL, since = "5.4")
public #interface IndicativeSentencesSeparator {
String value();
}
So this way I could create my test with this new interface, and passing the parameter but also making it optional to use, like this,
#DisplayName("My Test")
#DisplayNameGeneration(DisplayNameGenerator.IndicativeSentencesGenerator.class)
#IndicativeSentencesSeparator(" --> ")
class MyTestClass { //Some test methods and stuff }
To get the this new class in the implementation, I used the java method class.getAnnotation(classType) in the class that you're trying to extract the value, sending by parameter the class to find, in this case the interface I created.
IndicativeSentencesSeparator separator =
myTestClass.getAnnotation(IndicativeSentencesSeparator.class);
And finally to get the parameter used the getter value,
String parameter = separator.value();
Related
I would like to have extension function and use logger from kotlin-logging and have constants inside companion object.
My function:
fun String.toFoo(): Foo {
logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
...
}
Question is where I should put val logger = KotlinLogging.logger {} and MY_CONST since I cannot use companion object with an extension function?
If you just want you logger to be a singleton you can make an object that contains and instance of the logger and reach it from there.
Object LoggerSingleton( val logger = KotlinLogging.logger{})
Then in your extension function
fun String.toFoo(): Foo {
LoggerSingleton.logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
}
Since an Object in Kotlin is guaranteed to have only one instance you won't have a different logger for each use of toFoo.
EDIT
To keep the desired class name
Use this signature
Like so:
Object StringLoggerSingleton( val logger = KotlinLogging.logger("String"))
I do not know what you want to accomplish with your logger, but I show you what I did already ;-)
Usually I put extension functions in its own file named similar to what the function is actually extending (e.g. either StringExtensionFunction or if is more related to its purpose and maybe only available if certain dependencies are available, I also did something like, e.g. JsoupExtensionFunctions (where there was a String.toJsoupHtml(), File.toJsoupXml(), etc.)).
If I then need constants I just place them within that file, e.g. by just writing something like:
private const val MY_CONST = "my_const_value"
No surrounding class, no surrounding object.
Regarding the logger... as loggers are usually tied to a certain name/class, I usually put a logger inside every (important) class or associate some logger to specific names... So I am not completely sure what your intent is here... If it's ok for you that the logger is returning the container of your extension function (maybe StringExtensionFunction.kt), then you can also put a logger-val inside that file similar to what I showed with MY_CONST.
If your intention was rather to reuse the callers logger, that might not work so easily... (the easiest would then probably be to pass it to the function, but usually you do not want that)... and other mechanisms may not really be worth it ;-)
How can I pass an annotion instance to a function?
I would like to call the java method AbstractCDI.select(Class<T> type, Annotation... qualifiers). But I don't know how to pass an annotation instance to this method.
Calling the constructor like
cdiInstance.select(MyClass::javaClass, MyAnnotation())
is not allowed and the #Annotation-Syntax cdiInstance.select(MyClass::javaClass, #MyAnnotation) is not allowed as parameter, too. How can I archive this?
When working with CDI you usually also have AnnotationLiteral available or at least you can implement something similar rather easy.
If you want to select a class using your annotation the following should do the trick:
cdiInstance.select(MyClass::class.java, object : AnnotationLiteral<MyAnnotation>() {})
Or you may need to implement your specific AnnotationLiteral-class if you require a specific value. In Java that would work as follows:
class MyAnnotationLiteral extends AnnotationLiteral<MyAnnotation> implements MyAnnotation {
private String value;
public MyAnnotationLiteral(String value) {
this.value = value;
}
#Override
public String[] value() {
return new String[] { value };
}
}
In Kotlin however, you can't implement the annotation and extend AnnotationLiteral or maybe I just did not see how (see also related question: Implement (/inherit/~extend) annotation in Kotlin).
If you rather want to continue using reflection to access the annotation then you should probably rather use the Kotlin reflection way instead:
ClassWithAnno::class.annotations
ClassWithAnno::methodWithAnno.annotations
Calling filter, etc. to get the Annotation you desire or if you know there is only one Annotation there, you can also just call the following (findAnnotation is an extension function on KAnnotatedElement):
ClassWithAnno::class.findAnnotation<MyAnnotation>()
ClassWithAnno::methodWithAnno.findAnnotation<MyAnnotation>()
One could annotate a method or field with the annotation an get it per Reflection:
this.javaClass.getMethod("annotatedMethod").getAnnotation(MyAnnotation::class.java)
Or According to Roland's suggestion the kotlin version of the above:
MyClass::annotatedMethod.findAnnotation<MyAnnotation>()!!
As suggested by Roland for CDI it is better to use AnnotationLiteral (see his post).
Is it possible to create extension of final classes like String? Like in swift it is possible to add additional methods inside a extension of final class.
For an example - I would like to create a method in String extension which will tell me String have valid length for password.
val password : String = mEdtPassword!!.getText().toString()
// how to define haveValidLength method in extension
val isValid : Boolean = password.haveValidLength()
Note - That example is just for a sake to understand usability of extension, not a real scenario.
yes, you can. Kotin extension method provides the ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator.
Below is an extension method for a String:
// v--- the extension method receiver type
fun String.at(value: Int) = this[value]
And the extension method code generated as Java below:
public static char at(String receiver, int value){
return receiver.charAt(value);
}
So an extension method in Kotlin is using delegation rather than inheritance.
Then you can calling an extension method like as its member function as below:
println("bar".at(1))//println 'a'
You also can write an extension method for the existing extension function, for example:
fun String.substring(value: Int): String = TODO()
// v--- throws exception rather than return "ar"
"bar".substring(1)
But you can't write an extension method for the existing member function, for example:
operator fun String.get(value: Int): Char = TODO()
// v--- return 'a' rather than throws an Exception
val second = "bar"[1]
Trying to add more detail, this answer might be helpful for someone.
Yes we can add additional methods to final classes like String. For an example I would like to add one method in String which will tell me that my String have valid number of characters for password or not.
So what I have to do is, I have ti create a below function which can be written in same class or at different separate class file.
fun String.hasValidPassword() : Boolean {
// Even no need to send string from outside, use 'this' for reference of a String
return !TextUtils.isEmpty(this) && this.length > 6
}
And now from anywhere call
val isValid : Boolean = password.haveValidLength()
Suggestion
If your application just has a single password validation, then there is no problem.
However, I don't suggest you write such a extension method hasValidPassword if the application has more than one validation. since the extension method is satically, you can't change your hasValidPassword in runtime. So if you want to change the validation in runtime, you should using a function instead, for example:
class PasswordRepository(private val validate:(String)->Boolean){
fun save(value:String){
if(validate(value)){
//TODO persist the password
}
}
}
val permitAll = PasswordRepository {true}
val denyAll = PasswordRepository {false}
permitAll.save("it will be persisted")
denyAll.save("it will not be persisted")
In other words, the extension method above violates Single Responsibility Principle, it does validation & string operations.
You can do that with extension functions in Kotlin. With extensions, you are able to add extra functionality to a class that you do or do not have access to; for example a legacy code base. In the example given in the Kotlin docs here, swap was added to MutableList<Int> which doesn't have swap originally. A this keyword is used that refers to the object that the swap functionality will operate on. In the example below, this refers to testList
val testList = mutableListOf(1, 2, 3)
testList.swap(0, 2)
From what I understand gmock (and I'm new to it) EXPECT_CALL allows for specifying how a method will behave when it's called (in this case I'm mostly interested in what it will return). But I could just as well define the method explicitly with its body. Example:
class Factory
{
int createSomething();
};
class MockFactory : public Factory
{
MOCK_METHOD0(createSomething, int());
};
int main()
{
...
int something(5);
MockFactory mockFactory;
EXPECT_CALL(mockFactory, createSomething()).WillRepeatedly(Return(something));
...
}
vs
class MockFactory : public Factory
{
int createSomething()
{
return 5;
}
};
Now, if createSomething were to behave differently (return different things) in different scenarios then obviously I should use EXPECT_CALL. But if it's going to always return the same thing wouldn't it be better to just explicitly define the method's body? (Note that other methods in the mocked class might still use EXPECT_CALL.)
When you define a method you miss all the flexibility that mocking that method can give you in the tests.
If you need to assert in a test that createSomething gets called, you can only do it if you have mocked it, not if you have a standard method definition. Not in this case, but in case of methods taking parameters, it's even better to have a mock.
If you need to set up a default action that your method should perform, even when you don't set any expectations on it, do so using ON_CALL macro in the SetUp member function of a TestFixture.
I have a problem while using jmockit for the following scenario. Did a research on the web, but couldn't locate the answers yet.
In the record phase, I am setting the expectation on an object that is partially mocked. While doing it, I would like to mock a private method with single parameter. But i don't really concerned with that parameter value. I want to match all invocation of that particular private method with any instance of argument passed to it. How do I do it in Jmockit. Is there a way?
new Expectations(student) {
{
Deencapsulation.invoke(student, "setDepartment", (Department) any);
result = new Delegate<Student>() {
public void setDepartment(Department dept) {
System.out.println("Mocked setDepartment() methodd.....");
}
};
}
};
In the above code, (Department) any can not be passed, since Deencapsulation.invoke(...) method doesn't accept null value.
Note the API documentation for the any field says:
"In invocations to non-accessible methods or constructors (for example, with Deencapsulation.invoke(Object, String, Object...)), use withAny(T) instead."
That is, you need to use withAny(Department.class) with the invoke(...) call.
As of JMockit v1.49, I use:
withInstanceOf(Department.class)
It works as expected.