I am writing test with usage of Java library Hamcrest and it's non-fluent API makes it impossible to reason about expression types when complex expression evolves, like:
.andExpect(JsonUnitResultMatchers.json()
.matches(CoreMatchers.anyOf(CoreMatchers.allOf(
JsonMatchers.jsonPartEquals("id", "123"),
JsonMatchers.jsonPartEquals("name", "test")))))
Is there always TRUE matcher that dumps type & value of currently active expression? Like:
.andExpect(JsonUnitResultMatchers.json()
.matches(CoreMatchers.anyOf(CoreMatchers.allOf(
Slf4jMatcher.logType(),
Slf4jMatcher.logTypeAndToString(),
ConsumerMatcher.apply(System.out::println),
JsonMatchers.jsonPartEquals("id", "123"),
JsonMatchers.jsonPartEquals("name", "test")))))
I don't like to step into Hamcrest code with debugger. It is unproductive to delve into someones internals.
I came up with ugly:
.andExpect(JsonUnitResultMatchers.json()
.matches(Matchers.hasItem(CoreMatchers.allOf(
new BaseMatcher() {
#Override
public boolean matches(Object item) {
log.info("type: {}", item.getClass());
log.info("toString: {}", item.toString());
return true;
}
#Override
public void describeTo(Description description) {}
},
JsonMatchers.jsonPartEquals("id", "123"),
JsonMatchers.jsonPartEquals("name", "test")))))
I hope there are some funny DSL...
Related
I would like to ask for a help and suggestions what is a correct approach in my case (probably its easy but I'm just starting with JUnit). Here is a part of my code
public boolean arrayListEmpty()
{
if(numericalSequence.isEmpty() == true)
return true;
else
return false;
}
This is a public method from model which I suppose i should test, it's just returning true if my numericalsequence is empty as you can see. I cant check it directly invoking numericalSequence.isEmpty (in controller where I need it) because it is private.
So obvious thing is to check
assertEquals(true, test.arrayListEmpty());
So my question is about suggestions what other asserts should I use/what cases should I predict which can come out. Should I in Test method fill numericalSequence with some values and assert it also? (for me its not necessary because any value inserted into sequence = not null but maybe it is not so easy)
First of all, welcome to Stack Overflow!
Looking at your question, it sounds like you're new to unit-testing (correct me if I'm wrong). So, I'll break my answers in to two sections; (1) answering your question, and (2) to give a general direction of how to write good tests and testable classes.
1. Answering your question
There are a couple more use cases you can think of here:
What happens if numericalSequence is null?
What if numericalSequence has 1 element?
What if numericalSequence has a null element?
Some of the cases above may not be possible depending on how your class is set up, but it's a test worth having so that any changes to the class that violates the "previously agreed behavior" of one of these test cases would fail.
2. Writing good tests
There are no strict guidelines on what to do in order to write good tests, however, if you structure your code to be testable, you'll find that writing good tests becomes easier, and would be less of chore. Allow me to explain.
NOTE: This is not a comprehensive guide, but is meant to start your journey in to the path of how to write better code, and better tests
So assume a class that needs to be tested is written like this:
class MyClass {
// NOTE: This is not `final`
private List<Integer> numericalSequence;
public MyClass() {
this.numericalSequence = new ArrayList<>();
}
public void doSomething(Integer x) {
if (x < 0) {
numericalSequence = new ArrayList<>();
} else {
numericalSequence.add(2 * x);
}
}
public boolean arrayListEmpty() {
// NOTE: Your sample code can be reduced to this one-liner
return numericalSequence.isEmpty();
}
}
Here are some of the flaws in the above code:
doSomething method allows nullable (boxed integer) values and so can cause NullPointerException in the first if statement.
The numericalSequence member is not final and hence the code that sets it to null is valid inside the doSomething method
The arrayListIsEmpty method does not check if numericalSequence is null
If I want to test how arrayListIsEmpty behaves when numericalSequence is null, or has null elements, it is hard to do so, unless you know how to get the class to that state.
If the class was re-written to the following:
class MyClass {
private final List<Integer> numericalSequence;
public MyClass() {
this(new ArrayList<>());
}
// Should be made public only if the classes that use this one needs to
// initialize this instance with the sequence. Make this package-private
// otherwise.
public MyClass(List<Integer> sequence) {
this.numericalSequence = sequence;
}
public void doSomething(int x) {
if (x < 0) {
// COMPILE ERROR: Cannot assign to a final member
// numericalSequence = new ArrayList<>();
numericalSequence.clear();
} else {
numericalSequence.add(2 * x);
}
}
public boolean arrayListEmpty() {
return numericalSequence == null || numericalSequence.isEmpty();
}
}
A few things to note about the above structure:
There are two constructors; the default invokes the one that takes a list of integers as the sequence, so that it reuses any logic that both would need to share. There are no logic in this example, but hopefully you'll come across one soon.
The doSomething() method doesn't accept Integer value, but int value that makes sure that x is never null (Java numerical primitive types cannot be null). This also means, numericalSequence cannot contain null values through doSomething().
Since numericalSequence can be initialized from outside of this class, the arrayListEmpty() method makes sure to check that numericalSequence is either null is truly empty.
Now you can write test cases like so:
#Test
public void arrayListEmpty_WhenListIsNull() {
MyClass test = MyClass(null);
assertTrue(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListIsEmpty() {
MyClass test = MyClass();
assertTrue(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListHasOnlyOneNonNullElement() {
List<Integer> sequence = new ArrayList<>();
sequence.add(0);
MyClass test = new MyClass(sequence);
assertFalse(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListHasOnlyOneNullElement() {
List<Integer> sequence = new ArrayList<>();
sequence.add(null);
MyClass test = new MyClass(sequence);
assertFalse(test.arrayListEmpty());
}
Since doSomething() adds/clears the sequence, when writing tests for doSomething() make sure the call and verify the state of the class by checking the return value of arrayListEmpty().
For example:
#Test
public void doSomething_WhenInputLessThanZero() {
List<Integer> sequence = new ArrayList<>();
sequence.add(0);
MyClass test = new MyClass(sequence);
test.doSomething(-1);
assertTrue(test.arrayListEmpty());
}
My intention was to show a couple of things:
Structure your tests cases to be small and concise
Design your class to be easily testable
Hope this helps.
The context
I have a simple method that I'm testing using the mockito library.
The problem
I have a error:
"[MockitoHint] ReceiveServiceTest.testGetFileDto (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at .ReceiveServiceTest.testGetFileDto(ReceiveServiceTest.java:46)
[MockitoHint] ...args ok? -> at ReceiveService.getFileDto(ReceiveService.java:28)
I dont understand way.
The code
#RunWith(MockitoJUnitRunner.class)
public class ReceiveServiceTest {
private List<File> filePaths = new ArrayList<>();
#InjectMocks
private ReceiveService receiveService;
#Mock
private FindFiles findfiles;
#Mock
private ReadByte readByte;
#Before
public void before() {
filePaths.add(new File("d://folder//test1_message_received"));
filePaths.add(new File("d://folder//test2_message_received"));
filePaths.add(new File("d://folder//test3_message_received"));
}
#Test
public void testGetFileDto() throws IOException {
// Given
byte[] resultByteArr = new byte[1028];
when(findfiles.getPathFiles()).thenReturn(filePaths);
when(readByte.readByteArrFromFile(new File("d://folder//test3_message_received"))).thenReturn(resultByteArr);
List<MessageDTO> result = receiveService.getFileDto();
//some assert
}
method
#Autowired
private FindFiles findFiles;
#Autowired
private ReadByte readByte;
public List<MessageDTO> getFileDto() throws IOException {
List<MessageDTO> fileDtos = new ArrayList<>();
for (File file : findFiles.getPathFiles()) {
fileDtos.add(new MessageDTO(Base64.getEncoder().encode(readByte.readByteArrFromFile(new File(file.getPath()))),
file.getName(), "zip", null));
}
return fileDtos;
}
I think mocks are not being initialized. Please initialize the mocks in the #Before method.
#Before
public void init() {
initMocks(this);
}
This should solve the problem I guess.
Here is solution for my problem. I added foreach loop. Now the mock works, but byte [] is different than what it should return.
// Given
byte[] mockByteArr = new byte [2048];
when(findfiles.getPathFiles()).thenReturn(filePaths);
for (File filePath : filePaths) {
when(readByte.readByteArrFromFile(new File(filePath.getPath()))).thenReturn(mockByteArr);
}
//When
List<MessageDTO> result = receiveService.getFileDto();
//Then
assertEquals(3, result.size());
assertEquals(mockByteArr, result.get(1).getContent());
Your problem is, that you create a new object in the following line:
when(readByte.readByteArrFromFile(new File("d://folder//test3_message_received"))).thenReturn(resultByteArr);
Mockito needs to know which real object is passed to the method so that it can return the appropriate thenReturn-value. So if you pass the actual reference into it, your code will work, but also only if you specify all the values which are listed. Otherwise you may get a NullPointerException.
By the way, calling new File(file.getPath()) seems redundant to me. You can just use file instead.
So with the following your code might work better:
when(readByte.readByteArrFromFile(filePaths.get(0)).thenReturn(resultByteArray);
but then you need to specify it for all entries.
Alternatively, use a Matcher instead:
when(readByte.readByteArrFromFile(ArgumentMatchers.any(File.class))).thenReturn(resultByteArr);
or specify the actual argument matching you require as matchers can be very powerful in that regard.
Previously the answer contained the following, which is still true, but not as concise as the answer above:
It's been a long time since I last used mocks (and I am even proud of it ;-)).
The message already states that one should consult the javadoc and there I found the following:
Those are hints - they not necessarily indicate real problems 100% of the time.
Nonetheless, I believe the problem is with the following statement:
when(readByte.readByteArrFromFile(new File("d://folder//test3_message_received"))).thenReturn(resultByteArr);
I think you need to specify a return for every entry in the filePaths or make the call more generic using Matchers.any() (or any other appropriate Matcher).
all of the samples i've seen online with regard to custom parametersuppliers have something like:
List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
list.add(PotentialAssignment.forValue("teams", "giants"));
list.add(PotentialAssignment.forValue("teams", "jets"));
list.add(PotentialAssignment.forValue("teams", "niners"));
return list;
now, the question i have is: what does the first argument to PotentialAssignment.forValue(arg1, arg2) do? Nothing i've seen online has explained the significance of it.
thanks
The first parameter of PotentialAssignment.forValue is the "name" of the value. It is not used, if your #Theory method passes, but if it fails, it is used to assemble the error message. Here is an example:
#RunWith(Theories.class)
public class CustomParameterSupplierTest {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#ParametersSuppliedBy(FooSupplier.class)
public #interface Foo {}
public static class FooSupplier extends ParameterSupplier {
#Override
public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
return Arrays.asList(
PotentialAssignment.forValue("one", 1),
PotentialAssignment.forValue("two", 2)
);
}
}
#Theory
public void test(#Foo int foo) {
assertThat(foo, is(1));
}
}
If this test is executed with Junit 4.11 you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test(two)
By the way, in the upcoming release JUnit 4.12 the error reporting is further improved and you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test("2" <from two>)
I'm working on MySQL using .Net Connector 6.3.6 and created Entity models on VS 2010. I'm planning to write a generic method that would add an EntityObject to its corresponding table. Here is how it looks:
public void AddToTable(ObjectContext dataContext, string tableName, EntityObject tableObj)
{
try
{
Type type = dataContext.GetType();
string methodName = "AddTo" + tableName;
MethodInfo methodInfo = type.GetMethod(methodName);
PropertyInfo propInfo = dataContext.GetType().GetProperty(tableName);
Object[] parameters = new Object[] { Convert.ChangeType(tableObj, propInfo.PropertyType) };
methodInfo.Invoke(dataContext, parameters);
}
catch (Exception e)
{
edit://gonna handle it appropriately here!
}
}
ObjectContext will be the actual ObjectContext class.
But I'm getting exception saying "object must implement IConvertible" when I use Covert.ChangeType() on an EntityObject.
How to overcome this problem?
Edit: FYI, my main intention is to make write a method which is as generic as possible so that no casting to a particular table type would be required.
Thanks,
Alerter
You're reinventing the wheel.
public void AddToTable<TEntity>(ObjectContext dataContext, TEntity tableObj)
{
dataContext.CreateObjectSet<TEntity>().AddObject(tableObj);
}
And please don't eat exceptions.
Followed the following generalized repository pattern:
[link]http://www.codeproject.com/Articles/37155/Implementing-Repository-Pattern-With-Entity-Framew[link] It is very intuitive and fits my requirement :)
All,
I am currently using JUnit 4 for writing test cases. I am fairly new to JUnit and finding it difficult to test my main class which takes arguments. I have specified the arguments to my JUnit test class by:
1 > Right click JUnit test class
2 > Goto Run As -> Run Configurations
3 > Select the Arguments tab and specify a value (I have entered an invalid argument i.e. the main class expects the command line argument to be converted to an int and I am passing a String value that cannot be converted to int)
However, the main class that I am testing, if the command line argument cannot be converted to a int, than I throw IllegalArgumentException. However, the JUnit does not show the testMain() method as Error or Failure. I don't think my setup is right for the JUnit class. Can anyone please guide me where I am going wrong
To test your class main method simply write something like:
#Test(expected = IllegalArgumentException.class)
public void testMainWithBadCommandLine()
{
YourClass.main(new String[] { "NaN" });
}
Change the main() method to something like this:
public static void main(String[] args)
{
MyClass myclass = new MyClass(args);
myclass.go();
}
Move the code that was in main() to the new method go(). Now, your test method can do this:
public void myClassTest()
{
String[] args = new String[]{"one", "two"}; //for example
MyClass classUnderTest = new MyClass(testArgs);
classUnderTest.go();
}
Firstly the arguments should be in the program arguments section. Normally the launching point of the application that's the main method doesn't need to be tested if you design the app to be testable.
Refactor the class
public static class ArgumentValidator
{
public static boolean nullOrEmpty(String [] args)
{
if(args == null || args.length == 0)
{
throw new IllegalArgumentException(msg);
}
//other methods like numeric validations
}
}
You can now easily test the nullOrEmpty method using junit like
#Test(expected = IllegalArgumentException.class)
public void testBadArgs()
{
ArgumentValidator.nullOrEmpty(null);
}
I think this is a better approach