I am using JUNIT to produce a test suite on a triangle project named (TriangleClassifier.java) and I am trying to read the below method that is to test the a,b,c sides and the expected output based on those values and then apply this to JUNIT although does not accept my test code and produces the following error. Any suggestions? thanks
JUNIT Error
expected: java.lang.String<ISOSCELES> but was: TriangleClassifier$TriangleType<ISOSCELES>
junit.framework.AssertionFailedError
at TestSuite.test1(TestSuite.java:9)
Method trying to test
public static TriangleType classify (int a, int b, int c) {
if (isInRange(a) & isInRange(b) & isInRange(c)) {
if (isTriangle(a, b, c)) {
if (a == b & b == c) {
return TriangleType.EQUILITERAL;
} else if (a !=b & a != c & b != c) {
return TriangleType.SCALENE;
} else {
return TriangleType.ISOSCELES;
}
} else {
return TriangleType.NOT_A_TRIANGLE;
}
} else {
return TriangleType.OUT_OF_RANGE;
}
}
TestSuite.java
import static org.junit.Assert.*;
import org.junit.Test;
public class TestSuite {
#Test
public void test1() {
assertEquals("ISOSCELES", TriangleClassifier.classify(100, 100, 1));
}
}
UPDATE
Have tried your suggestions of changing
assertEquals("ISOSCELES", TriangleClassifier.classify(100, 100, 1));
to
assertEquals(TriangleType.ISOCELES,TriangleClassifier.classify(100,100,1));
ALTHOUGH my JUNIT now produces a new error - Uncompilable source code - Erroneous tree type:
java.lang.RuntimeException
at TestSuite.test1(TestSuite.java:9)
AND
the below line where TriangleType is flaging an error with cannot find symbol - assertEquals(TriangleType.ISOCELES,TriangleClassifier.classify(100,100,1));
ERROR Screenshot
public enum TriangleType
By writing
assertEquals("ISOSCELES", TriangleClassifier.classify(100, 100, 1));
you tell JUNIT, that you expect the function to return the String "ISOSCELES". What your function actually returns is the constant TriangleType.ISOSCELES.
Change your assertion to
assertEquals(TriangleType.ISOSCELES, TriangleClassifier.classify(100, 100, 1));
Your assertion is comparing a String to a TriangleType, so naturally, these won't be equal. You want to write
assertEquals(TriangleType.ISOSCELES, TriangleClassifier.classify(100,100,1));
which compares a TriangleType to a TriangleType.
Update
Since it appears that you've defined TriangleType as an inner type of TriangleClassifier, you will either need to add an import statement for it to your class, or refer to it as
assertEquals(TriangleClassifier.TriangleType.ISOSCELES, TriangleClassifier.classify(100,100,1));
Without going too deeply into your algorithms, the error is most obviously highlighted by the return type of your classify method contrasted against your unit test. classify returns a TriangleType enumeration, but your JUnit test is expecting an object of type String to be returned. Since the two types are not equivalent, the expected and actual values cannot be equal. Hence the test fails.
Either change your test to expect a TriangleType, or your classify method to return a String.
Two things here:
You really have not much of a clue what you are doing. When you are on such a level that simple compiler error messages prevent you from making progress, you probably have to step back and focus on learning the java basics again before overburdening yourself with unit-testing and such things (although unit tests are a great thing, and one should start using them as early as possible).
Then I would suggest that you stop using assertEquals.
JUnit has another assert, called assertThat. You can use that like:
assertThat(TriangleClassifier.classify(100,100,1), is(TriangleType.ISOSCELES));
... and here the compiler would already give you a hint that
assertThat(TriangleClassifier.classify(100,100,1), is("some string"));
is invalid.
Further reading on assertThat/is: here
Related
I'm stuck on a unit test I'm working on for the following:
if(dsIn.getItemNumber(1,"CC_FY_APPR_OBLIG_AMT") != null)
{
dsIn.setItemNumber(1, "CC_FY_UNOBLIG_AMT", Double.valueOf(newValueIn)-dsIn.getItemNumber(1,"CC_FY_APPR_OBLIG_YTD_AMT"));
}
else
{
dsIn.setItemNumber(1, "CC_FY_UNOBLIG_AMT", Double.valueOf(newValueIn));
}
I was able to mock the second case when getItemNumber() == null but I am struggling with finding the proper way to verify that the first case is executing and returning the appropriate number after the subtraction. I have tried writing the following test case for it :
#Test
public void testUncheckedApproved() throws TRDIException, IOException{
Mockito.when(dsIn.getItemNumber(1,"CC_FY_APPR_OBLIG_YTD_AMT")).thenReturn(4.0);
evaluate();
Mockito.verify(dsIn, Mockito.times(1)).setItemNumber(1, "CC_FY_UNOBLIG_AMT", Double.valueOf(newValueIn)) - Mockito.verify(dsIn, Mockito.times(1)).setItemNumber(1, "CC_FY_APPR_OBLIG_YTD_AMT",
Double.valueOf(newValueIn));
}
This obviously doesn't work, and I've also tried to verify each method separately, but that is not the way to do it. The 'verify' method is incorrect. I just need to figure out this line.
I think the second verify is wrong. You posted:
Mockito.verify(dsIn, Mockito.times(1)).setItemNumber(1, "CC_FY_UNOBLIG_AMT", Double.valueOf(newValueIn)) - Mockito.verify(dsIn, Mockito.times(1)).setItemNumber(1, "CC_FY_APPR_OBLIG_YTD_AMT",
Double.valueOf(newValueIn));
But it should be:
double d1=Mockito.verify(dsIn).getItemNumber(1,"CC_FY_APPR_OBLIG_YTD_AMT");
double d2=Double.valueOf(newValueIn)-d1;
Mockito.verify(dsIn).setItemNumber(1, "CC_FY_UNOBLIG_AMT", d2);
(I omitted to check for the number of times these methods are invoked, since they should be invoked just once).
I am somewhat new to test driven development and am trying to determine whether I have a problem with my approach to unit testing.
I have several unit tests (let's call them group A) that test whether my method's return is as expected.
I also have a unit test "B" whose passing condition is that an IllegalArgumentException is thrown when my method is given invalid input.
The unit tests in group A fail when the method is given invalid input since the method needs valid input to return correctly.
If I catch the exception, unit test "B" will fail, but if I don't catch the exception, the tests in group A will fail.
Is it OK to have unit tests fail in this way, or can I modify the code in some way so that all tests always pass?
Am I doing TDD all wrong?
Here's a notion of my code for more clarity:
public class Example{
public static String method(String inputString, int value){
if(badInput){
throw new IllegalArgumentException();
}
//do some things to inputString
return modifiedInputString;
}
}
public class ExampleTests{
#Test
public void methodReturnsIllegalArgumentExceptionForBadInput(){
assertThrows(IllegalArgumentException.class, ()->{Example.method(badInput,badValue);})
}
//"Group A" tests only pass with valid input. Bad input causes IllegalArgumentException
#Test
public void methodReturnsExpectedType(){
assertTrue(actual == expected);
}
#Test
public void methodReturnsExpectedValue(){
assertTrue(actual == expected);
}
#Test
public void methodReturnsExpectedStringFormat(){
assertTrue(actual == expected);
}
}
As you've correctly noted in the comment the problem is with too broad test setup and too implicit tests.
Tests are much more readable when they are self-contained on the business level. Common test setup should be focused on setting up technical details, but all business setup should be within each test itself.
Example for your case (a conceptual example, must be reworked to match the details of your implementation):
#Test
public void givenWhatever_whenDoingSomething_methodReturnsExpectedType(){
given(someInputs);
Type result = executeSut(); //rename executeSut to actual function under test name
assertTrue(result == expected);
}
This way by just looking at a test a reader knows what scenario is being tested. Common test setup and helper functions such as given abstract away technical details, so the reader does not get distracted at the first inspection. If they are interested, the details are always available - but are usually less important, such can be hidden.
i am using eclemma and trying to increase my test coverage:
so far this is my code:
public RolesResponse findRolesByTenant(RolesRequest rolesRequest)
{
RolesResponse rolesResponse = new RolesResponse();
List<Role> roleList = null;
if (StringUtils.isNotBlank(rolesRequest.getTenantCode()))
{
roleList = roleFunctionService.getAllRolesAndFunctionsByTenant(rolesRequest.getTenantCode());
}
if (CollectionUtils.isNotEmpty(roleList))
{
rolesResponse.setRoles(roleList);
}
else
{
rolesResponse.setError(LayerContextHolder.getErrorObject());
}
return rolesResponse;
}
and here is my test:
#Test
public void findRolesByTenantTest()
{
RolesRequest rolesRequest = new RolesRequest();
rolesRequest.setTenantCode("test");
ErrorObject errorObject = new ErrorObject();
RolesResponse rolesResponse = rolesProcessService.findRolesByTenant(rolesRequest);
Assert.assertNull(rolesResponse.getError());
}
the only line eclemma is highlighting in red is this one:
rolesResponse.setError(LayerContextHolder.getErrorObject());
can someone help me in constructing the final test needed to cover this line
thanks
I'm really not a fan of your test anyway - what are you trying to prove by the error being null? That the list came back with something? Also, are you certain that your service will return the result you want in your test every single time?
Don't think of tests in terms of coverage; this will lead to brittle tests and tests that give a false sense of security. What you want to do is write tests that cover each condition that the code could encounter, and the line coverage can follow from that.
From your code, I see two cases.
roleFunctionService#getAllRolesByFunctionAndTenant can return a non-empty list.
It's implied that the resultant rolesResponse#roles contains whatever was in the list provided by the method, and this should be verified.
It's also implied that there is no error set on the object, so it should be null.
roleFunctionService#getAllRolesByFunctionAndTenant can return an empty list
Either the resultant rolesResponse#roles are empty or null; it'd be better if it were empty.
It's implied that there is an error on the object, which is specifically provided by LayerContextHolder.getErrorObject(). You should check to see that it's exactly that.
You'll get to the whole approach of writing this test through the use of a mocking framework.
I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.
I am taking this code snippet from K&B practice exams.
public class Later {
public static void main(String[] args) {
boolean earlyExit = new Later().test1(args);
if (earlyExit) assert false; // LINE 5
new Later().test2(args);
}
boolean test1(String[] a) {
if (a.length == 0) return false;
return true;
}
private void test2(String[] a) {
if (a.length == 2) assert false; // LINE 13
}
}
The answer in K&B states that, LINE-5 AND LINE-13 are in-appropriate use of assertions.
I would like to know why. Here is my observation after reading topic of assertion from
K&B.
1.I do understand, LINE 5 is in-appropriate because it is using assertion to validate
command line arguments. Assertions should never be used to validate command line arguments.
2.In answer, it also states that, LINE 13 is also in-appropriate use of assertions. Good practice
in assertions states that, you can use assertions to validate arguments to your private methods. So
my question is why LINE 13 is in-appropriate use of assertions.
Any insights over this will be helpful.
Assertion (assert keyword in java) are used to verify the correctness of an invariant in code, precondition or postcondition. They are used to test your assumption in code to catch inconsistent state and are - usually - an indicator of a bug or a unwanted flow execution.
Assertion are disabled as default because they shouldn't throw in production and asserted code is not executed
public class AssertionTest {
private boolean productionCode(){
System.out.println("Prodution code executed");
return true;
}
private void assertion() {
assert productionCode();
}
}
with assertion enabled output is :
Prodution code executed
and with assertion disabled output is...nothing! so be carefully
Syntax:
assert <boolean expression>; throws an AssertionError if is false
assert <boolean expression> : <expression with value> throws AssertionError with detail message if is false
In your example
private void test2(String[] a) {
if (a.length == 2) assert false; // LINE 13
}
you are using it in a wrong way because the right way is
private void test2(String[] a) {
assert (a.length != 2);
}
means: a MUST have a lenght not equals 2 else is an error
Read here for Oracle documentation.
Assertions are used to check for code invariants. You should never do input validation by using assertions, because usually they are disabled at runtime, that's why LINE 5 is inappropriate.
Q:Assertion advocates that we can use assertion to validate private methods.
A: Yes, you can validate private method's arguments with assertions, because they are not visible to the public - i.e. if assertion fails it means that there is a logic/programmers mistake somewhere in the caller, but I'd recommend using if/else/exceptions constructs. As I said above, you should never validate public methods, because in practice everyone can pass anything to the method and if assertions are disabled bad things will happen :)