I am trying to have proper assertion (with implicit null checks) for a property of a list element.
The first assertion is working as expected, except that it will generate no proper error message if actual is null.
The second is supposed to provide proper null check for actual, but it's not compiling.
Is there an option tweak the second assertion to make it work?
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class ExampleTest {
private static class Sub {
private String value;
public String getValue() {
return value;
}
}
private static class Example {
private List<Sub> subs;
public List<Sub> getSubs() {
return subs;
}
}
#Test
void test() {
Example actual = null;
assertThat(actual.getSubs())//not null safe
.extracting(Sub::getValue)
.contains("something");
// assertThat(actual)
// .extracting(Example::getSubs)
// .extracting(Sub::getValue)//not compiling
// .contains("something");
}
}
For type-specific assertions, extracting(Function, InstanceOfAssertFactory) should be used:
assertThat(actual)
.extracting(Example::getSubs, as(list(Sub.class)))
.extracting(Sub::getValue) // compiles
.contains("something");
Assertions.as(InstanceOfAssertFactory) is an optional syntax sugar to improve readability
InstanceOfAssertFactories.list(Class) provides the list-specific assertions after the extracting call
Related
How can i use the values from hashset (the docid and offset) to the reduce writable so as to connect map writable with reduce writable?
The mapper (LineIndexMapper) works fine but in the reducer (LineIndexReducer) i get the error that it can't get string as argument when i type this:
context.write(key, new IndexRecordWritable("some string");
although i have the public String toString() in the ReduceWritable too.
I believe the hashset in reducer's writable (IndexRecordWritable.java) maybe isn't taking the values correctly?
I have the below code.
IndexMapRecordWritable.java
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
public class IndexMapRecordWritable implements Writable {
private LongWritable offset;
private Text docid;
public LongWritable getOffsetWritable() {
return offset;
}
public Text getDocidWritable() {
return docid;
}
public long getOffset() {
return offset.get();
}
public String getDocid() {
return docid.toString();
}
public IndexMapRecordWritable() {
this.offset = new LongWritable();
this.docid = new Text();
}
public IndexMapRecordWritable(long offset, String docid) {
this.offset = new LongWritable(offset);
this.docid = new Text(docid);
}
public IndexMapRecordWritable(IndexMapRecordWritable indexMapRecordWritable) {
this.offset = indexMapRecordWritable.getOffsetWritable();
this.docid = indexMapRecordWritable.getDocidWritable();
}
#Override
public String toString() {
StringBuilder output = new StringBuilder()
output.append(docid);
output.append(offset);
return output.toString();
}
#Override
public void write(DataOutput out) throws IOException {
}
#Override
public void readFields(DataInput in) throws IOException {
}
}
IndexRecordWritable.java
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.HashSet;
import org.apache.hadoop.io.Writable;
public class IndexRecordWritable implements Writable {
// Save each index record from maps
private HashSet<IndexMapRecordWritable> tokens = new HashSet<IndexMapRecordWritable>();
public IndexRecordWritable() {
}
public IndexRecordWritable(
Iterable<IndexMapRecordWritable> indexMapRecordWritables) {
}
#Override
public String toString() {
StringBuilder output = new StringBuilder();
return output.toString();
}
#Override
public void write(DataOutput out) throws IOException {
}
#Override
public void readFields(DataInput in) throws IOException {
}
}
Alright, here is my answer based on a few assumptions. The final output is a text file containing the key and the file names separated by a comma based on the information in the reducer class's comments on the pre-condition and post-condition.
In this case, you really don't need IndexRecordWritable class. You can simply write to your context using
context.write(key, new Text(valueBuilder.substring(0, valueBuilder.length() - 1)));
with the class declaration line as
public class LineIndexReducer extends Reducer<Text, IndexMapRecordWritable, Text, Text>
Don't forget to set the correct output class in the driver.
That must serve the purpose according to the post-condition in your reducer class. But, if you really want to write a Text-IndexRecordWritable pair to your context, there are two ways approach it -
with string as an argument (based on your attempt passing a string when you IndexRecordWritable class constructor is not designed to accept strings) and
with HashSet as an argument (based on the HashSet initialised in IndexRecordWritable class).
Since your constructor of IndexRecordWritable class is not designed to accept String as an input, you cannot pass a string. Hence the error you are getting that you can't use string as an argument. Ps: if you want your constructor to accept Strings, you must have another constructor in your IndexRecordWritable class as below:
// Save each index record from maps
private HashSet<IndexMapRecordWritable> tokens = new HashSet<IndexMapRecordWritable>();
// to save the string
private String value;
public IndexRecordWritable() {
}
public IndexRecordWritable(
HashSet<IndexMapRecordWritable> indexMapRecordWritables) {
/***/
}
// to accpet string
public IndexRecordWritable (String value) {
this.value = value;
}
but that won't be valid if you want to use the HashSet. So, approach #1 can't be used. You can't pass a string.
That leaves us with approach #2. Passing a HashSet as an argument since you want to make use of the HashSet. In this case, you must create a HashSet in your reducer before passing it as an argument to IndexRecordWritable in context.write.
To do this, your reducer must look like this.
#Override
protected void reduce(Text key, Iterable<IndexMapRecordWritable> values, Context context) throws IOException, InterruptedException {
//StringBuilder valueBuilder = new StringBuilder();
HashSet<IndexMapRecordWritable> set = new HashSet<>();
for (IndexMapRecordWritable val : values) {
set.add(val);
//valueBuilder.append(val);
//valueBuilder.append(",");
}
//write the key and the adjusted value (removing the last comma)
//context.write(key, new IndexRecordWritable(valueBuilder.substring(0, valueBuilder.length() - 1)));
context.write(key, new IndexRecordWritable(set));
//valueBuilder.setLength(0);
}
and your IndexRecordWritable.java must have this.
// Save each index record from maps
private HashSet<IndexMapRecordWritable> tokens = new HashSet<IndexMapRecordWritable>();
// to save the string
//private String value;
public IndexRecordWritable() {
}
public IndexRecordWritable(
HashSet<IndexMapRecordWritable> indexMapRecordWritables) {
/***/
tokens.addAll(indexMapRecordWritables);
}
Remember, this is not the requirement according to the description of your reducer where it says.
POST-CONDITION: emit the output a single key-value where all the file names are separated by a comma ",". <"marcello", "a.txt#3345,b.txt#344,c.txt#785">
If you still choose to emit (Text, IndexRecordWritable), remember to process the HashSet in IndexRecordWritable to get it in the desired format.
I m trying create unit tests for one project.I m facing a problem because when I try control the result of an interface(mock). When the code get the Interface variable that return a NullPointerException.
Firstly I tried #Override the method in my test class (ClassA), but it don't work. After that I tried mock the interface object and control the comportment with Mockito.When().tehnReturn();
I will put here my code, I read some solutions but none works.
My Interface:
#FunctionalInterface
public interface Interface {
UpdateXResponse process(UpdateXRequest request) throws Exception;
}
The class I want to test:
#Service(ClassA.class)
public class ClassA extends VService implements UpdateX {
#Reference
#Inject
private Interface interface;
#Inject
public ClassA(...) {...}
#Override
public UpdateXResponse process(UpdateXRequest request) throws Exception {
UpdateXResponse response = initResponse(context, request, new UpdateXResponse());
UpdateXInput input = request.getInput();
UpdateXOutput output = new UpdateXOutput();
response.setOutput(output);
try {
firstMethodCall(...);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
private void firstMethodCall(...) throws Exception {
TypeF typeF = callInterfaceMethod(...);
...
}
/**
* Orchestrates Interface service
*/
protected TypeF callInterfaceMethod(...) {
...
request.setInput(input);
request.setHeader(header);
InterfaceResponse response = interface.process(request); // LINE ERROR - In this step interface is NULL when the test get this
return response;
}
}
And finally my class test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = {ClassA.class,Interface.class} )
public class WithPowerMockUnitTest{
#InjectMocks
private ClassA classA;
private Interface interface;
#Before
public void setUp() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
Interface = Mockito.mock(Interface.class);
when(Interface.process(Mockito.any(InterfaceRequest.class))).thenReturn(serviceUnavailableResponse);
}
#Test
public void testh() throws SOAException {
InterfaceResponse res = interface.process(Mockito.any(InterfaceRequest.class)); // There all run ok. The interface is not null and return what i expected.
System.out.println("RES "+res);
}
#Test
public void test() {
assertNotNull(classA); // not null
assertNotNull(interface); // not null
}
#Test
public void newTest() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
UpdateXResponse response = ClassA.process(updateXRequest()); // PROBLEM!! When that get the LINE ERROR the interface is null! WHY?
}
}
I put some comments in the lines where the problem exists for me.
public interface A{
Response process(Request r) throws Exception;
}
public class B{
private Class_That_Override_Interface_method ctoim;
public Response function(){
X res = method_B();
}
protected X method_B(){
response res = ctoim.process(request); // That ctoim is always NULL when the test get that line/call
}
}
Thanks
You're missing the #Mock annotation on your Interface variable.
Therefore the mock is not injected into your classA and the newTest() fails. (In this case remove Interface = Mockito.mock(Interface.class); from the setUp method).
Alternativly remove the #InjectMocks annotation and create your class under test manually passing your mock into the constructor.
For this specific case (assuming its a different case from the last question)
there doesn't seem to be a need to involve PowerMockito. So unless you left out some relevant parts you might as well just use the MockitoJUnitRunner.
Ps.:
Also remeber what I said last time about compilable examples?
interface is a keyword and can't be used for variables.
You should also aim to write variables identical all the times (not Interface and interface / classA and ClassA)
And in case you haven't read it yet check out the help section about minmal reproducible examples.
Edit:
I fogot to mention that the line interface.process(Mockito.any(InterfaceRequest.class)); in testh() is actually invalid syntax. You should use ArgumentMatchers only for parameters of mocked methods.
Also consider adding the MockitoAnnotations.initMocks(this); to your setUp method, when using the PowerMockRunner.
Assume you have type-building macro, interface invoking #:autoBuild using aforementioned macro, class implementing the interface and class extending it. Macro will fail if the class doesn't contain specific method.
Like so:
Macro.hx
package;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
class Macro
{
macro public function build():Array<Field>
{
var fields = Context.getBuildFields();
for (field in fields) {
if (field.name == "hello") {
//Do some modifications
return fields;
}
}
Context.error('${Context.getLocalClass().toString()} doesn\'t contain a method `hello`', Context.currentPos());
return null;
}
}
I.hx
package;
#:autoBuild(Macro.build())
interface I {}
Foobar.hx
package;
class Foobar implements I
{
public function new() {}
public function hello(person:String)
{
return 'Hello $person!';
}
}
Foo.hx
package;
#:keep
class Foo extends Foobar {}
As you can see, we're checking if field "hello" exists. However, Context.getBuildFields contains only fields of current class, and build will fail for Foo.
This is where my idea comes in: Why not just check if any ancestor was already processed? We'll change Macro.hx to reflect just that:
Macro.hx
package;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
class Macro
{
macro public function build():Array<Field>
{
var c = Context.getLocalClass().get();
if(isAncestorAlreadyProcessed(c)) {
return null;
}
var fields = Context.getBuildFields();
for (field in fields) {
if (field.name == "hello") {
//Do some modifications
c.meta.add(":processed", [], c.pos);
return fields;
}
}
Context.error('${Context.getLocalClass().toString()} doesn\'t contain a method `hello`', Context.currentPos());
return null;
}
private static function isAncestorAlreadyProcessed(c:ClassType)
{
if (c.meta.has(":processed")) return true;
if (c.superClass == null) return false;
return isAncestorAlreadyProcessed(c.superClass.t.get());
}
}
And for the main questions: Do I misunderstand haxe macro type building? Is there a more viable way of making this work? Does my code fail in specific scenarios? Are there any harmful side-effects caused by this code?
I'm trying to resolve this issue.
No, this is the way to go, use metadata to store information of the classes you processed (source).
Another way, if you don't need this information at runtime, is to use a static array on a dedicated class like here. Afterwards, you can even push this information in your compiled code, see here.
Hope that helps.
I am using XStream for serializing and de-serializing an object. For example, a class named Rating is defined as follows:
Public Class Rating {
String id;
int score;
int confidence;
// constructors here...
}
However, in this class, the variable confidence is optional.
So, when the confidence value is known (not 0), an XML representation of a Rating object should look like:
<rating>
<id>0123</id>
<score>5</score>
<confidence>10</confidence>
</rating>
However, when the confidence is unknown (the default value will be 0), the confidence
attribute should be omitted from the XML representation:
<rating>
<id>0123</id>
<score>5</score>
</rating>
Could anyone tell me how to conditionally serialize a field using XStream?
One option is to write a converter.
Here's one that I quickly wrote for you:
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public class RatingConverter implements Converter
{
#Override
public boolean canConvert(Class clazz) {
return clazz.equals(Rating.class);
}
#Override
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context)
{
Rating rating = (Rating) value;
// Write id
writer.startNode("id");
writer.setValue(rating.getId());
writer.endNode();
// Write score
writer.startNode("score");
writer.setValue(Integer.toString(rating.getScore()));
writer.endNode();
// Write confidence
if(rating.getConfidence() != 0)
{
writer.startNode("confidence");
writer.setValue(Integer.toString(rating.getConfidence()));
writer.endNode();
}
}
#Override
public Object unmarshal(HierarchicalStreamReader arg0,
UnmarshallingContext arg1)
{
return null;
}
}
All that's left for you to do is to register the converter, and provide accessor methods (i.e. getId, getScore, getConfidence) in your Rating class.
Note: your other option would be to omit the field appropriately.
public class Temp
{
List<T> values = new List<T>;
static Temp()
{
System.Console.WriteLine("static constructor");
}
public Temp()
{
System.Console.WriteLine("general constructor");
}
}
Also please explain me when will the List object will be created and with what type it is created.
}
It appears the field gets initialized first, then the static constructor is called, then the constructor.
class Test
{
string variable = new Func<string>(() =>
{
Console.WriteLine("field initializer");
return "VARIABLE";
})();
static string staticvariable = new Func<string>(() =>
{
Console.WriteLine("static field initializer");
return "STATICVARIABLE";
})();
static Test()
{
System.Console.WriteLine("static constructor");
}
public Test()
{
System.Console.WriteLine("general constructor");
}
}
Test t = new Test();
outuput:
static field initializer
static constructor
field initializer
general constructor
[edit]
Oops sorry, it was a non-static field and I didn't notice it.
The static ctor will be called first.
Then values list will be second and the the ctor.
Read about beforefieldinit here.