How to fix this problem with assertEquals in Junit? - java

Please help me with the following problem, My Junit test fails because my output is
"09:39:43.704 [main] INFO by.iba.gomel.ShapeController - 145"
But i need just "145" ShapeController.LOGGER.info("{}", ShapeController.sum);
#Test
public void testSumma() {
final Shape[] newShapes = new Shape[5];
ShapeController.initializeArray(newShapes);
ShapeController.summa(newShapes);
Assert.assertEquals("these objects should be equal", "145", this.log.getLog());
}

If you are not changing the log format and the class name you can use this.log.getLog().split("ShapeController - ")[1].
But be wary of such hard-coded things. Anyways if you change something this test case will break and notify you.

You can use Java Library such as Hamcrest to make an assertion in a sentence if it ends with the number or word, such as 1 :
assertThat("myStringOfNote", endsWith("Note"))
This can be translated into your use case as :
assertThat(this.log.getLog(), endsWith("145"))

Related

Reuse production code in tests : good or bad idea? (Or can I use the same code in test and production)?

We have a piece of production code in our application that reads raw DB rows something like that:
List<Map<String, Object>> results =
txnNamedJdbcTemplate.queryForList(
transactionDbQueries.getProperty(QUERY_FETCH_REPORT_DETAILS).trim(), paramMap);
, then it does a whole load of field transformations to produce an object of desired structure:
private Report extractReportData(long reportId, List<Map<String, Object>> results) {
Map<String, Object> reportRow = results.get(0);
Timestamp completeTs = (Timestamp) reportRow.getOrDefault(RS_PARAM_END_DATETIME, null);
Timestamp lastOpenedTs =
(Timestamp) reportRow.getOrDefault(RS_PARAM_LAST_OPENED_DATETIME, null);
String reportData =
reportRow.get(RS_PARAM_REPORT_DATA) == null
? StringUtils.EMPTY
: ((PGobject) reportRow.get(RS_PARAM_REPORT_DATA)).getValue();
Duration executionTime =
reportRow.containsKey(RS_PARAM_DURATION)
? Duration.ofSeconds(Long.parseLong(reportRow.get(RS_PARAM_DURATION).toString()))
: null;
String reportRunLevel = (String) reportRow.getOrDefault(RS_PARAM_ACCESS_LEVEL, null);
boolean reportOpened = (Boolean) reportRow.getOrDefault(RS_PARAM_OPENED_STATUS, Boolean.FALSE);
String reportCategory = (String) reportRow.getOrDefault(RS_PARAM_REPORT_CATEGORY, null);
Long scheduledId =
reportRow.get(RS_PARAM_SCHEDULED_ID) != null
? Long.parseLong(reportRow.get(RS_PARAM_SCHEDULED_ID).toString())
: null;
return Report.builder()
.reportId(reportId)
.reportName((String) reportRow.get(RS_PARAM_REPORT_NAME))
.reportType((String) reportRow.get(RS_PARAM_REPORT_TYPE))
.reportCategory(reportCategory)
.reportStatusDesc(
ReportStatus.values()[(Integer) reportRow.get(RS_PARAM_STATUS_ID) - 1].getDesc())
.submittedBy((String) reportRow.get(RS_PARAM_USER_NAME))
.submittedById((int) reportRow.get(RS_PARAM_USER_ID))
.submittedTime((Timestamp) reportRow.get(RS_PARAM_SUBMIT_DATETIME))
.completedTime(completeTs)
.lastOpeningTime(lastOpenedTs)
.reportData(reportData)
.reportRunLevel(reportRunLevel)
.opened(reportOpened)
.executionTime(executionTime)
.scheduledId(scheduledId)
.build();
}
I know it's not the prettiest bit of code, but that's legacy system and is beside the point.
Now, I had to test that code to make sure we can read the same object and verify the fields, so I had the following 3 scenarios:
Clone this code in a test class. I've built a test utility that does just that. Clearly, that resulted in duplication of the same un-pretty code, which is not ideal.
An alternative way would be to outsource this code to some utility class and let both prod and test code use it, for the sake of avoiding duplication.
Also, there is a way to change access modifier of the production class and let test that.
That is an integration test that uses proper DB instance so using mocks isn't gonna do - we need to read actual data. The example is actually not the best and is only for illustration. The main question: do we reuse production code in the tests or is it best to duplicate it?
I strongly lean toward option #1, on the premise that if we introduce a bug in the transformation in the prod code - how do we detect it? For that, I believe code segregation is the best way.
Are there any other opinions or reasons behind these, please?
If you going to duplicate the code in test scope, what if some bug fix has been added in future and what if your test did't alert you about something happened on your production code flow?Also think about how you maintain your duplicate code in future.
Usually tests are not only meant to validate your present code.But they also document and feedback/system that will notify any changes/breakages in code.
If you couldn't write a test case for your piece, then its a time to refactor your code.
On a practical note it's not always good idea to dismantle the existing working piece, it may need bit time and depth knowledge on history of code base and strong test suite.But its worth to get our hands little dirty
I would suggest any one below,
Refactor your code, align it with Single Responsibility and cover each unit with test case(as you stated atleast you can move them to some util).
integration test
use powermock or any similar tool to test private methods(Note : Some organisation may not like tools like powermock for security concerns)

Eclipse JUnit assertEquals(String, String) - disable square bracket diff in Failure Trace

JUnit assertEquals Changes String
In short: assertEquals("Hello World", "HelloWorld"); appears in the Failure Trace as expected:<Hello[ ]World> but was:<Hello[]World>
Great. Definitely didn't waste my time trying to figure out why the heck my parser was randomly throwing square brackets around.
How do I disable this?
I am using Eclipse 4.19.0 for Java, JUnit 4.10.
You cannot.
These brackets are added by junit.framework.ComparisonCompactor that is being used in org.junit.ComparisonFailure assertion error's getMessage method (this error is being thrown by assertEquals btw)
// ComparisonFailure class
public String getMessage() {
return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
}
in ComparisonCompactor these brackets are hardcoded and it seems that there is no configuration that can be provided, also ComparisonCompactor cannot be injected (the same for ComparisonFailure - you are not able to provide custom implementation for them)
public class ComparisonCompactor {
private static final String ELLIPSIS= "...";
private static final String DELTA_END= "]";
private static final String DELTA_START= "[";
// ...
private String compactString(String source) {
String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
As far as I see even in Junit 4.13 it looks exactly the same so even bumping up dependency will not help here (however you could give a try to Junit5 that with usage of Assertions.assertEquals will produce expected: <Hello world> but was: <Helloworld> output - but obviously it won't be just bumping up dependency version)
By the way Eclipse has nothing to do with it, the same output you will get in other IDEs (or in console)
What I would suggest (however it's not an answer for your question) is to use assertion library like AssertJ that can give you more control but also make you assertions more fluent.
An example in AssertJ would look like
assertThat("Hello World").isEqualTo("HelloWorld");
and is producing
Expecting:
<"Hello World">
to be equal to:
<"HelloWorld">
but was not.

How make JUnit print assertion results

How can I get the results of my JUnit assertions to be printed [to standard output]?
I have some tests like this:
#Test
public void test01()
{
Position p = getPositionAt('a', 1);
assertNotNull("a1 exists", p);
assertNotNull("figure exists a1", p.getFigure());
p = getPositionAt('a', 2);
assertNotNull("exists a2", p);
assertNull("figure exists a2", p.getFigure());
p = getPositionAt('b', 1);
assertNotNull("exists b1", p);
assertNull("figure exists b1", p.getFigure());
}
This is the printed output format I am hoping to get:
a1 exists -success
figure exists a1 -success
exists a2 -success
figure exists a2 -succcess
exists b1 -succcess
figure exists b1 -failed
Is there way to do this using runners and suites? Or does there exist any assertSuccess(), assertFailed() methods?
First, you have two issues not one. When an assertion fails, an AssertionError exception is thrown. This prevents any assertion past this point from being checked. To address this you need to use an ErrorCollector.
Second, I do not believe there is any way built in to JUnit to do this. However, you could implement your own methods that wrap the assertions:
public static void assertNotNull(String description, Object object){
try{
Assert.assertNotNull(description, object);
System.out.println(description + " - passed");
}catch(AssertionError e){
System.out.println(description + " - failed");
throw e;
}
}
All the assertXXX methods have a form that allows for displaying a String on error:
assertNotNull("exists a2", p); // prints "exists a2" if p is null
There is no particular value in printing a message on success.
EDIT
Junit typically provides 2 forms of an assert. To follow the example above, you can test for a null value in 1 of 2 ways:
assertNotNull(p)
or
assertNotNull("my message on failure", p)
The framework will print the error messages with no other effort required by you (it's provided by the framework).
To test for exceptions you would use the following pattern:
try{
someCall();
catch(Exception e){
fail(): // exception shouldn't happen, use assertTrue(true) if it should
}
Again, there are versions of these methods for adding a message
Check the API
One last resort option is to pair each assert with a corresponding System.out.println, though obviously that is less than ideal. Still, it will solve the problem if all else fails.
Existing Answers/Comments here contain enough info to understand how to print something based on JUnit assertions - but they also explain how doing so is probably not what you actually want to do, and is probably missing the point of running unit tests in the first place.
You should be viewing the results of the tests themselves, instead of trying to print something while you don't understand how/where to view test results themselves.
Now then how/where to view results themselves depends on how you are running your tests - you need to understand how you are running your tests, and then research how to view test results according to how you are running them. Here are a few (but not limited to) examples:
Running tests in IntelliJ
Running tests in Eclipse
Running tests on command line
Running tests in Jenkins

WebDriver + TestNG - How to handle test results

I'm quite new to WebDriver and TestNG framework. I've started with a project that does a regression test of an e-commerce website. I'm done with the login and registration and so on. But there is something that I don't quite understand.
Example, I have this easy code that searches for a product.
driver.get(url + "/k/k.aspx");
driver.findElement(By.id("q")).clear();
driver.findElement(By.id("q")).sendKeys("xxxx"); //TODO: Make this dynamic
driver.findElement(By.cssSelector("input.submit")).click();
Now I want to check if xxxx is represented on the page. This can be done with
webdriver.findElement(By.cssSelector("BODY")).getText().matches("^[\\s\\S]*xxxxxx[\\s\\S]*$")
I store this in a Boolean and check if its true or false.
Now to the question, based on this Boolean value I want to say that the test result is success or fail. How can I do that? What triggers a testNG test to fail?
TestNG or any other testing tool decides success or failure of a test based on assertion.
Assert.assertEquals(actualVal, expectedVal);
So if actualVal and expectedVal are same then test will pass else it will fail.
Similarly you will find other assertion options if you using any IDE like Eclipse.
If you want to stop your test execution based on the verification of that text value, then you can use Asserts. However, if you want to log the outcome of the test as a failure and carry on, you should try using soft assertions, which log the verification as passed or failed and continue with the test. Latest Testng comes equipped to handle this - info at Cedric's blog
write this code where your if condition fails
throw new RuntimeException("XXXX not found: ");
u can use throw exception, and each method which will cal this meth should also throw Excetion after method name or you can use try catch. sample:
protected Boolean AssertIsCorrectURL(String exedctedURL) throws Exception {
String errMsg = String.format("Actual URL page: '%s'. Expected URL page: '%s'",
this.driver.getCurrentUrl(), exedctedURL);
throw new Exception(errMsg);
}
You can do this.
boolean result = webdriver.findElement(By.cssSelector("BODY")).getText().matches("^[\s\S]xxxxxx[\s\S]$")
Assert.assertTrue(result);

How to check if a parameter contains two substrings using Mockito?

I have a line in my test that currently looks like:
Mockito.verify(mockMyObject).myMethod(Mockito.contains("apple"));
I would like to modify it to check if the parameter contains both "apple" and "banana". How would I go about this?
Just use Mockito.matches(String), for example:
Mockito.verify(mockMyObject).
myMethod(
Mockito.matches("(.*apple.*banana.*)|(.*banana.*apple.*)"
)
);
Since Java 8 and Mockito 2.1.0, it is possible to use Streams as follows:
Mockito.verify(mockMyObject).myMethod(
Mockito.argThat(s -> s.contains("apple") && s.contains("banana"))
);
thus improving readability
I think the easiest solution is to call the verify() multiple times:
verify(emailService).sendHtmlMail(anyString(), eq(REPORT_TITLE), contains("Client response31"));
verify(emailService).sendHtmlMail(anyString(), eq(REPORT_TITLE), contains("Client response40"));
verify(emailService, never()).sendHtmlMail(anyString(), anyString(), contains("Client response30"));
Maybe this is not relevant anymore but I found another way to do it, following Torsten answer and this other answer. In my case I used Hamcrest Matchers
Mockito.verify(mockMyObject).myMethod(
Mockito.argThat(Matchers.allOf(
Matchers.containsString("apple"),
Matchers.containsString("banana"))));
You can also use Mockito's AdditionalMatchers:
Mockito.verify(mockMyObject).myMethod(
AdditionalMatchers.and(Mockito.contains("apple"), Mockito.contains("banana")));
More info https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/AdditionalMatchers.html#and(T,T)

Categories