Spock: test name and outcome in setup() cleanup() methods - java

I am wondering if it is possible to make the following data available in a Spock test's lifecycle methods:
test name in the setup() method
test name and test outcome in the cleanup() method
The reason I am asking is that I would like send these metadata to a data sink without the need to touch each and every test.
Thanks!
Martin

Try this.specificationContext.iterationInfo.name in setup(). Not sure if it works. In general specificationContext is the place where I'd be looking for such data.

Update from Opal's answer:
It is now (Spock 1.1) specificationContext.currentIteration.name
For the record, you could also use
#Rule
TestName testName = new org.junit.rules.TestName()
...
println "name: $testName.methodName"
... but there seems no point.
For the other question, getting the outcome: I couldn't find a way of getting this from Spock's SpecificationContext.
I took a quick look at org.junit.rules.TestWatcher ... but with Spock this seemed unable to detect a failed test.

Related

How can I pass a dynamic parameter-that I will create with some random library- in testNg xml?

I want to pass a dynamic parameter to a test case from testng xml, my parameter is something like:
String dynamicParameter=generateRandomStringForMail();
Here is my testcase:
#Test()
public void customerCreatorAllProducts () throws Exception {
setup();
Functions.pages.LoginPage login = PageFactory.initElements(driver, Functions.pages.LoginPage.class);
login.navigateRegisterPage().createFixedPasswordCustomerRequiredFields(dynamicParameter);
}
I will be using this parameter in other cases as well, how can i do this from testng.xml or with something else?
I am not familiar with testing.xml, but Mockito immediately comes to mind for this: http://mockito.org.
add Mockito to your project (e.g. through the build.gradle page)
add the import to your test file:
import static org.mockito.Mockito.*;
within your test class, create a mock of the class which has the generateRandomStringForMail() method. In my current project, I have
DefaultFileService mockFileService = mock(DefaultFileService.class);
define what you want the method to return under these test conditions, e.g.
when(mockFileService.generateRandomFileName()).thenReturn("fileName");
Whenever your tests need to use the result of the method in question, you can use "fileName", because you have told the test environment to give this response. My project has a method to update the image file associated with an inventory item, which process includes using the DefaultFileService to generate a random file name, then passing the image file and the new file name to the DefaultFileService to save the file in the system. My test code can't see or guess what file name would actually be produced, but my 'when' line above has resolved that problem for the purposes of testing my QuiltController class:
quiltController.update(data, mockFile);
verify(mockFileService).save(mockFile, "fileName"); // confirms the save() method was called with the expected parameters
It feels pretty similar to what you are trying to do, so hopefully that helps you proceed if you do want to explore Mockito. Don't be surprised if you need to refactor some of your work to make it more testable. I did, and have better code as a result. Give it a go :)

How to resolve Unneccessary Stubbing exception

My Code is as below,
#RunWith(MockitoJUnitRunner.class)
public class MyClass {
private static final String code ="Test";
#Mock
private MyClassDAO dao;
#InjectMocks
private MyClassService Service = new MyClassServiceImpl();
#Test
public void testDoSearch() throws Exception {
final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
CriteriaDTO dto = new CriteriaDTO();
dto.setCode(code);
inspectionService.searchEcRcfInspections(dto);
List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
inspectionsSummaryList.add(dto);
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
}
}
I am getting below exception
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.java:838)
at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.java:34)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:49)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Please help me how to resolve
At first you should check your test logic. Usually there are 3 cases. First, you are mocking the wrong method (you made a typo or someone changed tested code so that mocked method is no longer used). Second, your test is failing before this method is called. Third, your logic falls in wrong if/switch branch somewhere in the code so that mocked method is not called.
If this is the first case you always want to change the mocked method for the one used in the code. With the second and the third it depends. Usually you should just delete this mock if it has no use. But sometimes there are certain cases in parametrized tests, which should take this different path or fail earlier. Then you can split this test into two or more separate ones but that's not always good looking. 3 test methods with possibly 3 arguments providers can make your test look unreadable. In that case for JUnit 4 you silent this exception with either
#RunWith(MockitoJUnitRunner.Silent.class)
annotation or if you are using rule approach
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
or (the same behaviour)
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
For JUnit 5 tests you can silence this exception using this annotation provided in mockito-junit-jupiter package:
#ExtendWith(MockitoExtension.class)
#MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Replace #RunWith(MockitoJUnitRunner.class) with #RunWith(MockitoJUnitRunner.Silent.class).
For me neither the #Rule nor the #RunWith(MockitoJUnitRunner.Silent.class) suggestions worked. It was a legacy project where we upgraded to mockito-core 2.23.0.
We could get rid of the UnnecessaryStubbingException by using:
Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());
instead of:
when(mockedService.getUserById(any())).thenReturn(new User());
Needless to say that you should rather look at the test code, but we needed to get the stuff compiled and the tests running first of all ;)
Silent is not a solution. You need fix your mock in your test. See official documentation here.
Unnecessary stubs are stubbed method calls that were never realized during test execution (see also MockitoHint), example:
//code under test:
...
String result = translator.translate("one")
...
//test:
...
when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
...
Notice that one of the stubbed methods were never realized in the code under test, during test execution. The stray stubbing might be an oversight of the developer, the artifact of copy-paste or the effect not understanding the test/code. Either way, the developer ends up with unnecessary test code. In order to keep the codebase clean & maintainable it is necessary to remove unnecessary code. Otherwise tests are harder to read and reason about.
To find out more about detecting unused stubbings see MockitoHint.
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
The when here configures your mock to do something. However, you donot use this mock in any way anymore after this line (apart from doing a verify). Mockito warns you that the when line therefore is pointless. Perhaps you made a logic error?
Replace
#RunWith(MockitoJUnitRunner.class)
with
#RunWith(MockitoJUnitRunner.Silent.class)
or remove #RunWith(MockitoJUnitRunner.class)
or just comment out the unwanted mocking calls (shown as unauthorised stubbing).
This was already pointed out in this comment, but I think that's too easy to overlook: You may run into an UnnecessaryStubbingException if you simply convert a JUnit 4 test class to a JUnit 5 test class by replacing an existing #Before with #BeforeEach, and if you perform some stubbing in that setup method that is not realized by at least one of the test cases.
This Mockito thread has more information on that, basically there is a subtle difference in the test execution between #Before and #BeforeEach. With #Before, it was sufficient if any test case realized the stubbings, with #BeforeEach, all cases would have to.
If you don't want to break up the setup of #BeforeEach into many small bits (as the comment cited above rightly points out), there's another option still instead of activating the lenient mode for the whole test class: you can merely make those stubbings in the #BeforeEach method lenient individually using lenient().
As others pointed out it is usually the simplest to remove the line that is unnecessarily stubbing a method call.
In my case it was in a #BeforeEach and it was relevant most of the time. In the only test where that method was not used I reset the mock, e.g.:
myMock.reset()
Hope this helps others with the same problem.
(Note that if there are multiple mocked calls on the same mock this could be inconvenient as well since you'll have to mock all the other methods except the one that isn't called.)
Looking at a part of your stack trace it looks like you are stubbing the dao.doSearch() elsewhere. More like repeatedly creating the stubs of the same method.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
Consider the below Test Class for example:
#RunWith(MockitoJUnitRunner.class)
public class SomeTest {
#Mock
Service1 svc1Mock1;
#Mock
Service2 svc2Mock2;
#InjectMock
TestClass class;
//Assume you have many dependencies and you want to set up all the stubs
//in one place assuming that all your tests need these stubs.
//I know that any initialization code for the test can/should be in a
//#Before method. Lets assume there is another method just to create
//your stubs.
public void setUpRequiredStubs() {
when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
}
#Test
public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
// You forget that you defined the stub for svcMock1.someMethod or
//thought you could redefine it. Well you cannot. That's going to be
//a problem and would throw your UnnecessaryStubbingException.
when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
setUpRequiredStubs();
}
}
I would rather considering refactoring your tests to stub where necessary.
Well, In my case Mockito error was telling me to call the actual method after the when or whenever stub. Since we were not invoking the conditions that we just mocked, Mockito was reporting that as unnecessary stubs or code.
Here is what it was like when the error was coming :
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
}
then I just called the actual method mentioned in when statement to mock the method.
changes done is as below
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
//called the actual method here
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}
it's working now.
If you're using this style instead:
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
replace it with:
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
I had UnnecessaryStubbingException when I tried to use the when methods on a Spy object.
Mockito.lenient() silenced the exception but the test results were not correct.
In case of Spy objects, one has to call the methods directly.
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
class ArithmTest {
#Spy
private Arithm arithm;
#Test
void testAddition() {
int res = arithm.add(2, 5);
// doReturn(7).when(arithm).add(2, 5);
assertEquals(res, 7);
}
}
In case of a large project, it's difficult to fix each of these exceptions. At the same time, using Silent is not advised. I have written a script to remove all the unnecessary stubbings given a list of them.
https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b
We just need to copy-paste the mvn output and write the list of these exceptions using regex and let the script take care of the rest.
If you use any() when mocking, you have to relpace #RunWith(MockitoJUnitRunner.class) with
#RunWith(MockitoJUnitRunner.Silent.class).

How to change the #Test method dynamically in TestNG

This is more of a question on test automation framework design. Very hard indeed to summarize whole question in one line :)
I am creating a test automation framework using Selenium. Mostly I am accessing the data (methods name) from an excel file.
In my main Runner class I am getting a list of test cases. Each test case has a set of methods (can be same or different) which I have defined in a java class and executing each method using java reflection api. Everything is fine till this point.
Now I want to incorporate TestNG and reporting/logging in my automation suite. Problem is I cant use #Test for each method as TestNG considers #Test = 1 Test Case - but my 1 Test case might have more than 1 methods. My methods are more like a test steps for a test case, reason is I dont want repeat the code. I want to create a #Test dynamically calling different sets of methods and executing them in Java Or defining each teststeps for a #Test. I was going through the TestNG documentation, but could not able to locate any feature to handle this situation.
Any help is really appreciated and if you have any other thoughts to handle this situaton I am here to listen.
Did you try the following?
#Test(priority = 1)
public void step1() {
//code
}
#Test(priority = 2)
public void step2() {
//code
}
You need to use "priority" for each method, otherwise it won't work.

More Matchers recorded than the expected - Easymock fails from Maven and not from Eclipse

I'm having a strange problem with Easymock 3.0 and JUnit 4.8.2.
The problem only occurs when executing the tests from Maven and not from Eclipse.
This is the unit test (very simple):
...
protected ValueExtractorRetriever mockedRetriever;
...
#Before
public void before() {
mockedRetriever = createStrictMock(ValueExtractorRetriever.class);
}
#After
public void after() {
reset(mockedRetriever);
}
#Test
public void testNullValueExtractor() {
expect(mockedRetriever.retrieve("PROP")).andReturn(null).once();
replay(mockedRetriever);
ValueExtractor retriever = mockedRetriever.retrieve("PROP");
assertNull(retriever);
assertTrue(true);
}
And I get:
java.lang.IllegalStateException: 1 matchers expected, 2 recorded.
The weird thing is that I'm not even using an argument matcher. And that is the only method of the test! and to make it even worst it works from Eclipse and fails from Maven!
I found a few links which didn't provide me with an answer:
Another StackOverflow post
Expected Exceptions in JUnit
If I change the unit test and add one more method (which does use an argument matcher):
#Test
public void testIsBeforeDateOk() {
expect(mockedRetriever.retrieve((String)anyObject())).andReturn(new PofExtractor()).anyTimes();
replay(this.mockedRetriever);
FilterBuilder fb = new FilterBuilder();
assertNotNull(fb);
CriteriaFilter cf = new CriteriaFilter();
assertNotNull(cf);
cf.getValues().add("2010-12-29T14:45:23");
cf.setType(CriteriaType.DATE);
cf.setClause(Clause.IS_BEFORE_THE_DATE);
CriteriaQueryClause clause = CriteriaQueryClause.fromValue(cf.getClause());
assertNotNull(clause);
assertEquals(CriteriaQueryClause.IS_BEFORE_THE_DATE, clause);
clause.buildFilter(fb, cf, mockedRetriever);
assertNotNull(fb);
Filter[] filters = fb.getFilters();
assertNotNull(filters);
assertEquals(filters.length, 1);
verify(mockedRetriever);
logger.info("OK");
}
this last method passes the test but not the other one. How is this possible!?!?!
Regards,
Nico
More links:
"bartling.blogspot.com/2009/11/using-argument-matchers-in-easymock-and.html"
"www.springone2gx.com/blog/scott_leberknight/2008/09/the_n_matchers_expected_m_recorded_problem_in_easymock"
"stackoverflow.com/questions/4605997/3-matchers-expected-4-recorded"
I had a very similar problem and wrote my findings in the link below.
http://www.flyingtomoon.com/2011/04/unclosed-record-state-problem-in.html (just updated)
I believe the problem in on another test that affects your current test. The problem is on another test class and it affects you test. In order to find the place of the real problem, I advice to disable the problematic tests one by one till you notify the failing test.
Actually this is what I did. I disabled the failing tests one by one till I found the problematic test. I found a test that throws an exception and catches by "#extected" annotation without stopping the recording.
We had this problem recently, and it only reared its head when we ran the entire test suite (1100+ test cases). Eventually, I found that I could put a breakpoint on the test that was blowing up, and then step back in the list of tests that Eclipse had already executed, looking for the previous test case that had set up a mock incorrectly.
Our problem turned out to be somebody using EasyMock.anyString() outside of an EasyMock.expect(...) statement. Sure enough, it was done two tests before the one that was failing.
So essentially, what was happening is that the misuse of a matcher outside of an expect statement was poisoning EasyMock's state, and the next time we tried to create a mock, EasyMock would blow up.
I believe the first error message
java.lang.IllegalStateException: 1
matchers expected, 2 recorded.
means your mockedRetriever methods called twice but test expects it was called once. So your Eclipse and Maven's configuration differs.
And I have no reason to reset mock after test. Just keep in mind JUnit creates new class instance for every single test method.
EDITED:
What about the reason why the last test method passed the answer is:
expect(mockedRetriever.retrieve((String)anyObject())).andReturn(new PofExtractor()).anyTimes();
But in your first test method it is:
expect(mockedRetriever.retrieve("PROP")).andReturn(null).once();
as equivalent of:
expect(mockedRetriever.retrieve("PROP")).andReturn(null);

Unrooted Tests

When running all my tests in Eclipse (Eclipse 3.4 'Ganymede'), one test is listed under "Unrooted Tests". I'm using Junit 3.8 and this particular test extends TestCase. I do not see any difference between this test and the other tests. I don't remember seeing this occur in Eclipse 3.3 (Europa).
Clarification:
We haven't moved to JUnit 4.0 yet, so we are not using annotations. I also googled and it seemed like most people were having issues with JUnit 4, but I did not see any solutions. At this point the test passes both locally and in CruiseControl so I'm not overly concerned, but curious.
When I first saw this, though, it was on a failing test that only failed when run with other tests. This led me down the rabbit hole looking for a solution to the "Unrooted" issue that I never found. Eventually I found the culprit in another test that was not properly tearing down.
I agree, it does seem like an Eclipse issue.
Finally I found the solution. The problem is that you are not defining your test cases using annotations but are still doing it the "old way". As soon as you convert over to using annotations you will be able to run one test at a time again.
Here is an example of what a basic test should now look like using annotations:
import static org.junit.Assert.*; // Notice the use of "static" here
import org.junit.Before;
import org.junit.Test;
public class MyTests { // Notice we don't extent TestCases anymore
#Before
public void setUp() { // Note: It is not required to call this setUp()
// ...
}
#Test
public void doSomeTest() { // Note: method need not be called "testXXX"
// ...
assertTrue(1 == 1);
}
}
I was getting the "unrooted tests" error message as well and it went away magically. I believe it was due to the fact that I was using Eclipse with a Maven project. When I added a new method to my Test class and gave it the #Test annotation, it began getting the error message when I tried to run that one method using the "Run as Junit test" menu option; however, once I ran a maven build the unrooted tests message disappeared and I believe that is the solution to the problem in the future.
Run a maven build because it will refresh the class that JUnit is using.
If your class extends TestCase somewhere in its hierarchy, you have to use the JUnit 3 test runner listed in the drop down under run configurations. Using the JUnit 4 runner (the default I believe) causes that unrooted test phenomenon to occur.
I got this error because I renamed my test method and then tried to run the test in Eclipse by clicking on the same run configuration - referring to the old method which now didn't exist.
We solved the problem by making sure our test project was built. We had an issue in the build path which would not allow our test class to be compiled. Once we resolved the build path issue, the test compiled and the "new" method was able to be run. So we can assume that "Unrooted" tests also mean that they don't exist in the compiled binary.
I've never seen this -- but as far as I can tell from skimming Google for a few minutes, this appears as though it could be a bug in Eclipse rather than a problem with your test. You don't have the #Test annotation on the test, I assume? Can you blow the test away and recreate it, and if so do you get the same error?
Another scenario that causes this problem was me blindly copy/pasting a method that requires a parameter. i.e.
import org.junit.Test;
public class MyTest {
#Test
public void someMethod(String param) {
// stuff
}
}
You have a few simple solutions:
define the variable in the specific test method
add it as an instance variable to the test class
create a setup method and annotate it with #Before
For me, it was due to the project got build path issues. My maven dependencies configuration needs to be updated.
I had that problem and putting one "#Test" before the test method solved it!
like this:
#Test
public void testOne() { // ...
assertTrue(1 == 1);
}
These are the two scenarios that the Unrooted errors show up.
If you have missed the annotation #Test before the test.
#Test
public void foo(){
}
If it is a Gwt project and when two mock of the same object are defined. Lets say there is one class Class A and
#GwtMock
private A atest;
#GwtMock
private A a;
Then this will also show a Unrooted test error.
One other thing you can try is to upgrade your version of JUnit to at least 4.12.
I was experiencing this problem for a while with a class that extended one that used #RunWith(Parameterized.class).
After a while, and I'm sorry that I don't know precisely what I did to cause this, the 'Unrooted Tests' message went away, but the test still didn't run correctly. The constructor that should have accepted arguments from the #Parameters method was never getting called; execution jumped straight from #BeforeClass to #AfterClass.
The fix for that problem was to upgrade JUnit from the 4.8.1 it was using, to the latest (4.12). So maybe that could help someone else in the future.
I had the same problem with
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
you need the jar hamcrest.
same question 14539072: java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
I could the fix the issue by shifting from TestRunner ver 4.0 to 3 in run configurations for the individual test method.
Do not extend junit.framework.TestCase in your test class with junit1.4 and this should solve the problem
You are using Hamcrest? or another library to help in your test?. You are not using
import static org.junit.Assert.*;
Check if in your test you use:
import static org.hamcrest.MatcherAssert.assertThat;
or other assert isnĀ“t JUnit assert.
It turned out to be that my build path had some error...some jars were missing.
I reconfigured build path and it worked!
For me the problem was, that an exception was thrown in the #BeforeClass or #AfterClass methods. This will also cause tests to be categorized as unrooted.
I got this error with the test method name as "test"
#Test
public void test() {
// ... assertTrue(1 == 1);
}
I renamed the method and it worked
I ran into this problem by not also declaring the test to be static.
Maybe it's just a logical confusion about the goal of the method. Let's remember:
E.g. correct tagged test method:
#Test
#Transactional
#Rollback(true)
public void testInsertCustomer() {
(...)
}
-With Eclipse Junit plugin, You can run that test method using context menu over the method (E.g. at package explorer expanding the class and methods and selecting "testInsertCustomer()" method and from that item selecting "Run as >> JUnit test").
If you forgot "#Test" tag, or simply the method is not a test, but a (private or not) common method for using as utility for the other tests (e.g. "private fillCustomerObject()"), then the method does not require "#Test" tag, and simply you can not run it as a JUnit test!
It's easy that you could create a utility method and later you forgot the real goal of that method, so if you try to run it as a test, JUnit will shout "Unrooted Tests".
For me this problem was created by a real-time exception thrown in the #AfterClass method (take a look here for documentation):
Basically all the test methods succeeded but at the end of the class this method was failing. Therefore all the tests seems fine but there was on my Eclipse an additional "unrooted test" failed.
I got these errors for a maven project. I rebuild the project with mvn clean install.And the issue was solved
It actually told me there is a test with annotation: #RunWith(MockitoJUnitRunner.class)

Categories