Strange TestNg DataProvider MethodMatcherException - java-8

The DataProvider returns exactly the number and type of arguments required by the method.
This error is strange because if I substitute change the parameter and argument to use List<Experiment> instead of an Experiment[] then no exception is raised.
The method is:
#Test(dataProvider = "provideExperimentId")
public void testDetermineExperimentId(Experiment[] experiments, int experimentId, int expected)
{
mockExperimentId(experiments, experimentId)
assertEquals(fileParser.determineExperimentId(), expected);
}
The mockExperimentId(Experiment[], int) method sets up some when-then clauses,
and uses the parameters to customise some return values.
The data provider is:
#DataProvider
private Object[][] provideExperimentId(){
MockitoAnnotations.initMocks(this);
return new Object[][]{
{new Experiment[]{mockedExperiment}, 1, 1}
};
}
For some reason, I get the following mismatch exception, even though the number of arguments and the types are in agreement.
org.testng.internal.reflect.MethodMatcherException:
Data provider mismatch
Method: testDetermineExperimentId([Parameter{index=0, type=[Lcom.redacted.Experiment;, declaredAnnotations=[]}, Parameter{index=1, type=int, declaredAnnotations=[]}, Parameter{index=2, type=int, declaredAnnotations=[]}])
Arguments: [([Lcom.redacted.Experiment;) [mockedExperiment],(java.lang.Integer) 1,(java.lang.Integer) 1]
at org.testng.internal.reflect.DataProviderMethodMatcher.getConformingArguments(DataProviderMethodMatcher.java:45)
at org.testng.internal.Parameters.injectParameters(Parameters.java:796)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:973)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1116)
at org.testng.TestNG.runSuites(TestNG.java:1028)
at org.testng.TestNG.run(TestNG.java:996)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
However, changing the method and DataProvider to use a list raises no exception
#Test(dataProvider = "provideExperimentId")
public void testDetermineExperimentId(List<Experiment> experiments, int experimentId, int expected)
{
mockExperimentId(experiments.toArray(new Experiment[0]), experimentId)
assertEquals(fileParser.determineExperimentId(), expected);
}
The mockExperimentId(Experiment[], int) method sets up some when-then clauses,
and uses the parameters to customise some return values
#DataProvider
private Object[][] provideExperimentId(){
MockitoAnnotations.initMocks(this);
return new Object[][]{
{Arrays.asList(mockedExperiment), 1, 1}
};
}

Related

Use Method that returns an Int inside a Stream

I have a simple method :
public int getPrice(String bookingName)
{
//return the price of a booking
}
I also have the class :
public class Booking
{
String name;
...
}
I want to group the bookings in a map(key = name of the booking, value = getPrice(bookingName)) so I did :
public TreeMap<String, Integer> bookingForName() {
return bookings.stream().
collect(Collectors.groupingBy(Booking::getName,Collectors.summingInt(getPrice(Booking::getName))));
}
This doesnt' work it says :
Multiple markers at this line:
- The target type of this expression must be a functional interface
- The method getPrice(String) in the type Manager is not applicable for the arguments `(Booking::getName)`
How can I do?
Thanks!
Your getPrice() method takes a String, not a functional interface, so you can't call getPrice(Booking::getName), and even if you could, summingInt doesn't accept an int.
Change:
Collectors.summingInt(getPrice(Booking::getName))
to:
Collectors.summingInt(b -> getPrice(b.getName()))
Also note that Collectors.groupingBy returns a Map, not a TreeMap. If you must have a TreeMap, you should call a different variant of groupingBy.
public TreeMap<String, Integer> bookingForName() {
return bookings.stream()
.collect(Collectors.groupingBy(Booking::getName,
TreeMap::new,
Collectors.summingInt(b -> getPrice(b.getName()))));
}

How to exclude null value when using FsCheck Property attribute?

I need to write a simple method that receives a parameter (e.g. a string) and does smth. Usually I'd end up with two tests. The first one would be a guard clause. The second would validate the expected behavior (for simplicity, the method shouldn't fail):
[Fact]
public void DoSmth_WithNull_Throws()
{
var sut = new Sut();
Assert.Throws<ArgumentNullException>(() =>
sut.DoSmth(null));
}
[Fact]
public void DoSmth_WithValidString_DoesNotThrow()
{
var s = "123";
var sut = new Sut();
sut.DoSmth(s); // does not throw
}
public class Sut
{
public void DoSmth(string s)
{
if (s == null)
throw new ArgumentNullException();
// do smth important here
}
}
When I try to utilize the FsCheck [Property] attribute to generate random data, null and numerous other random values are passed to the test which at some point causes NRE:
[Property]
public void DoSmth_WithValidString_DoesNotThrow(string s)
{
var sut = new Sut();
sut.DoSmth(s); // throws ArgumentNullException after 'x' tests
}
I realize that this is the entire idea of FsCheck to generate numerous random data to cover different cases which is definitely great.
Is there any elegant way to configure the [Property] attribute to exclude undesired values? (In this particular test that's null).
FsCheck has some built-in types that can be used to signal specific behaviour, like, for example, that reference type values shouldn't be null. One of these is NonNull<'a>. If you ask for one of these, instead of asking for a raw string, you'll get no nulls.
In F#, you'd be able to destructure it as a function argument:
[<Property>]
let DoSmth_WithValidString_DoesNotThrow (NonNull s) = // s is already a string here...
let sut = Sut ()
sut.DoSmth s // Use your favourite assertion library here...
}
I think that in C#, it ought to look something like this, but I haven't tried:
[Property]
public void DoSmth_WithValidString_DoesNotThrow(NonNull<string> s)
{
var sut = new Sut();
sut.DoSmth(s.Get); // throws ArgumentNullException after 'x' tests
}

Spring SpEL chooses wrong method to invoke

I'm trying to evaluate the following SpEL expression (Spring-expression version 3.1.1):
T(com.google.common.collect.Lists).newArrayList(#iterable)
where #iterable is of type java.lang.Iterable.
Google Guava com.google.common.collect.Lists (version 14.0) does have a method newArrayList(Iterable) but for some reason SpEL chooses to invoke a different method: newArrayList(Object[])
I dived into the code and found the issue to be with org.springframework.expression.spel.support.ReflectiveMethodResolver implementation: it seems to be sensitive to the manner in which methods are sorted by the java.lang.Class::getMethods.
If 2 methods match the invocation (in the case one of the methods is varargs), the later method (in the order) will be invoked, instead of choosing the method that isn't varargs (which is more specific).
It seems like JDK doesn't guarantee the order the methods are sorted: different runs show different order.
Is there a way to overcome this issue?
You can use the collection projections of Spring EL to select all from iterable and convert it to list:
"#iterable.?[true]"
A simple example to test:
Iterable<Integer> it = () -> new Iterator<Integer>() {
private int[] a = new int[]{1, 2, 3};
private int index = 0;
#Override
public boolean hasNext() {
return index < a.length;
}
#Override
public Integer next() {
return a[index++];
}
};
Tmp tmp = new Tmp();
tmp.setO(it);
StandardEvaluationContext context = new StandardEvaluationContext(tmp);
ArrayList<Integer> list = parser.parseExpression("o.?[true]").getValue(context,
ArrayList.class);

NHibernate 3.3 Linq calling user defined function with bit parameter and bit result

I'm extending the NHibernate Linq provider and i wish to call a user defined that has both bit parameter[s] and return type.
Here's the SQL user defined function signature:
FUNCTION f_DocumentsFreeTextSearch
(
#docId int,
#searchString varchar(8000),
#searchTitle bit
)
RETURNS bit
Here's the "fake" extension method used for Linq usage:
public static class DialectExtensions
{
public static bool FreeText(this Document doc, string searchString, bool searchTitle)
{
return false;
}
}
Here's my LinqToHqlGeneratorsRegistry
public sealed class ExtendedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public ExtendedLinqToHqlGeneratorsRegistry()
{
DialectExtensions.FreeText(null, null, true)),
new FreeTextGenerator());
}
}
And here's my generator:
public class FreeTextGenerator : BaseHqlGeneratorForMethod
{
public FreeTextGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition(() => DialectExtensions.FreeText(null, null, true))
};
}
#region Overrides of BaseHqlGeneratorForMethod
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.MethodCall("dbo.f_documentsfreetextsearch", arguments.Select(a => visitor.Visit(a).AsExpression()).ToArray());
}
#endregion
}
This is the desired usage:
[TestMethod]
public void CanFreeText()
{
var query = SessionHolder.Current.Query<Document>();
var list = query.Where(d => d.FreeText("giorno", true)).ToList();
}
First problem: the above code causes an InvalidCastException:
Test method App.Tests.NHMapping.CanFreeText threw exception:
System.InvalidCastException: Unable to cast object of type
'NHibernate.Hql.Ast.HqlMethodCall' to type
'NHibernate.Hql.Ast.HqlBooleanExpression'.
Solved this way (not elegant but it works):
[TestMethod]
public void CanFreeText()
{
var query = SessionHolder.Current.Query<Document>();
var list = query.Where(d => d.FreeText("giorno", true) == true).ToList();
}
Now NHibernate executes the query, but the generated SQL is wrong:
Test method App.Tests.NHMapping.CanFreeText threw exception:
NHibernate.Exceptions.GenericADOException: could not execute query [
select [...] from dbo.DOCUMENTS document0_ where case when
dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT, #p0, #p1=1) then
1 else 0 end=#p2 ] Name:p1 - Value:giorno Name:p2 - Value:True
Name:p3 - Value:True [SQL: select [...] from dbo.DOCUMENTS document0_
where case when dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT,
#p0, #p1=1) then 1 else 0 end=#p2] --->
System.Data.SqlClient.SqlException: Incorrect syntax near '='.
Please not that the function call in the generated SQL has #p1=1 as third parameter, and that the WHERE clause is an inline CASE instead of
dbo.f_documentsfreetextsearch(document0_.IDDOCUMENT, #p0, #p1) = 1
as i expected.
If i change in my C# code the bool parameter and return type into Int32, everything just work well (but still not very elegant).
Any idea of how to get desired syntax to work?
Thanks in advance
Claudio
PS: sorry for lots of code and errors' text :P
seems you hit the same bug NH-2839 as i did when using usertype for boolean property. not much you can do about it now until this is fixed.

Sax XML Parser, switch does not take a string

We are trying to parse an xml file using sax parser, but we faced a problem using switch in :
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
switch(MyEnum.valueOf(qNam))
case tag1:
.......
break;
case tag2:
........
break;
case tag5:
..........
In each case we are populating some pojo objects.
The problem is when the parser encounter a tag that we are ignoring it throw an exception.
Exception is thrown because your own code calls MyEnum.valueOf with argument that is not guaranteed to be name of enum constant.
Because you want to ignore Exception, it is likely better to not have exception thrown at all. That can be done for example by adding following method to MyEnum:
public static boolean isOneOfTheValues(String val) {
for (MyEnum m: values()) {
if (m.name().equals(val)) {
return true;
}
}
return false;
}
and then not going in to switch statement at all if it is known to be unknown value:
if (!MyEnum.isOneOfTheValues(s)) {
return;
}
switch(MyEnum.valueOf(qNam))
If enumeration contains many constants, using rebuild set instead of iterating over return value of values() can provide better performance.

Resources