Let's say you have some 3rd-party library class that you want to extend, simply to add convenience methods to it (so you can call an inherited method with default parameters for example).
Using jUnit/jMock, is it possible to write an assertion / mock expection that tests that the correct inherited method is called?
For example, something like this:
class SomeClass extends SomeLibraryClass {
public String method(String code) {
return method(code, null, Locale.default());
}
}
How can I assert that method is being called?
You can make a further subclass inside your unit test that actually tells you:
public class MyTest {
boolean methodCalled = false;
#Test
public void testMySubclass(){
TestSomeClass testSomeClass = new TestSomeClass();
// Invoke method on testSomeclass ...
assertTrue( methodCalled);
}
class TestSomeClass extends SomeClass{
public String method(String code){
methodCalled = true;
}
}
}
Unit testing is more useful to verify the functionality of given methods, not to assert coverage. Unit tests that care more about what method got called know way more about the classes they are testing than they probably should, not to mention will be confusing to the reader.
Coverage tools like Cobertura or EMMA will tell you whether you properly covered your code.
It may indeed be better to only write integration tests in this case, but if you really want a unit test, you can have it just as easily as in any other case:
public class SomeClassTest
{
#Test
public void testMethod()
{
final String code = "test";
new Expectations()
{
SomeLibraryClass mock;
{
mock.method(code, null, (Locale) any);
}
};
new SomeClass().method(code);
}
}
This test uses the JMockit mocking API.
it's hard to tell without a more concrete example, but I'd guess that this ought to be an integration test--test the whole package together--rather than a unit test. Sometimes one can be too fine-grained with unit testing.
Related
I have a class called Availability.java and have two methods.
public Long getStockLevelStage() {
//some logic
getStockLevelLimit();
}
public Long getStockLevelLimit() {
String primaryOnlineArea = classificationFeatureHelper.getFirstFeatureName(productModel, FEATURE_CODE_PRODUCT_ONLINE_AREA_PRIMARY, language);
................
return new Long();
}
I'm writing a unit test class AvailabilityTest.java.
#RunWith(MockitoJUnitRunner.class)
public class AvailabilityTest {
#InjectMocks
private Availability availability = new Availability();
#Test
public void testGetStockLevelStage() {
availability.getStockLevelStage();
}
}
When I call availability.getStockLevelStage() method, it calls getStockLevelLimit() method. Is it possible to mock the internal method call?
In this case, I don't want getStockLevelLimit() to be executed, when getStockLevelStage() gets executes.
Please help.
Try this:
#RunWith(MockitoJUnitRunner.class)
public class AvailabilityTest {
#InjectMocks
#Spy
private Availability availability = new Availability();
#Test
public void testGetStockLevelStage() {
Mockito.doReturn(expectedLong).when(availability).getStockLevelLimit();
availability.getStockLevelStage();
}
}
Here is an article I wrote on Mockito Spying if you need a further read.
if getStockLevelLimit() has not to be executed during your test, it means in a some way you want to mock the class under test.
Doing it reduces the relevance and the authenticity of the behavior tested.
You should mock dependencies and not internal methods of the tested class.
I suppose you don't want to execute getStockLevelLimit() because it uses external dependency that you want to isolate or something of similar.
So you should mock and isolate which is behind getStockLevelLimit() and that doesn't make directly part of the Availability class.
I have a test class containing test cases for say blue and non-blue devices. If the parameter isBlue is set then it should run only those test case that have say the #Blue annotation. I am not sure how to implement this specific annotation that will achieve this functionality.
public class TestClass {
boolean isBlue = false;
#Before
public void setUp () {
isBlue = MyApplication.instance().isBlue();
}
#Test
public void testA () { ... }
#Test #Blue
public void testB() { ... }
}
In this example if isBlue is true then it should only run testB() otherwise it should run all test cases
Take a look at JUnit runners. Nice explanation of runners
You can create your own runner which will extend on BlockJUnit4ClassRunner.
You can override
#Override
protected List<FrameworkMethod> getChildren() {
// scan test class for methonds annotated with #Test
}
To additionally filter by methods that have your custom annotation set, and your property in the application is set as well.
I think you are on the wrong path.
You want your test cases to help identifying problems; and assist you in fixing them. Anything that "distracts" you from that purpose reduces the values of your unit tests.
Thus: don't put tests that have really "different" scope into the same test class. Especially from the point of view: how would you control what "MyApplication.instance()" would return? That sounds like a problem in itself.
Meaning: you want to have two independent tests; and those don't rely on some "static" object telling them something. They test what is in their scope; nothing else.
By using jUnit Assume
#Test
public void testA () {
assumeTrue(MyApplication.instance().isBlue());
...
}
A failing assumption in a #Before or #BeforeClass method will have the same effect as a failing assumption in each #Test method of the class.
public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}
How to spy parameter 'param' in nested method during getData() mock testing ?
Is it possible with Easymock 3 ?
Source code
public class ServiceLogic {
public void getData(){
// some business logic
serviceDAO.executeStatement(param);
}
}
Easymock test :
ServiceLogic _serviceLogicMock = EasyMock.createNiceMock(ServiceLogic.class);
ServiceDAO _serviceDAOMock = EasyMock.createNiceMock(ServiceDAO .class);
_serviceLogicMock.setServiceDAO(_serviceDAOMock);
//some other method calls -> .execute(...).andReturn(...);
EasyMock.replay(_serviceLogicMock);
//run
_serviceLogicMock.getData();
How to check with EasyMock whether executeStatement() method is called with correct parameter ?!
Your test does seem wrong:
Your unit test is about testing ServiceLogic why do you mock it then ?
Also you don't have any expectations on any interaction with your ServiceDAO mock.
As the question is tagged Mockito, I propose the following solution (minus the imports) that you can adapt to your code :
#RunWith(MockitoJUnitRunner.class)
public class ServiceLogicTest {
#Mock ServiceDAO serviceDAO;
#InjectMocks ServiceLogic serviceLogic;
#Test
public void ensure_executeStatement_is_called_with_right_param() throws Exception {
// given
String input = "Some input";
// when
serviceLogic.getDataFrom(input);
// then
verify(serviceDAO).executeStatement("expected param");
}
}
When writing tests, I like to use the BDD (Behavior Driven Development) style to guide me to what I want to test. I encourage you to practice it, you can have look at the wiki page.
So for your question, you should take a look at the verify line, it put the mock in a verification mode, so can actually verify that the method executeStatement is actually called with the argument value "expected param".
If you have more complex parameters, you can use some matchers using the Hamcrest library:
verify(serviceDAO).executeStatement(argThat(hasProperty("propertyName")));
Or you can use a Mockito's ArgumentCaptor in combination with the FEST-Assert library (usually my preferred approach):
ArgumentCaptor<ComplexArgument> argCaptor = ArgumentCaptor.forClass(ComplexArgument.class);
verify(serviceDAO).executeStatement(argCaptor.capture());
assertThat(argCaptor.getValue()).isNotNull().satisfies(myComplexArgumentCondition());
The main idea is to have understandable code, in production code and in test code.
For further reading have a look at the Mockito Javadoc.
Like #Brice, I prefer Mockito to EasyMock, but here's the EasyMock version that is closer to your original example since your example was EasyMock.
public class ServiceLogicTest {
#Test
public void ensure_executeStatement_is_called_with_right_param() throws Exception {
ServiceLogic _serviceLogicUT = new ServiceLogic();
ServiceDAO _serviceDAOMock = EasyMock.createNiceMock(ServiceDAO .class);
_serviceLogicUT.setServiceDAO(_serviceDAOMock);
String input = "Some input";
//some other method calls -> .execute(...).andReturn(...);
_serviceDaoMock.executeStatement("expected para"); // assuming a void method
EasyMock.replay(_serviceDaoMock);
// run
_serviceLogicUT.getDataFrom(input);
// verifies that the expected calls were made
EasyMock.verify(_serviceDaoMock);
}
}
EasyMock also has argument capture functionality. That would look like this:
public class ServiceLogicTest {
#Test
public void ensure_executeStatement_is_called_with_right_param() throws Exception {
ServiceLogic _serviceLogicUT = new ServiceLogic();
ServiceDAO _serviceDAOMock = EasyMock.createNiceMock(ServiceDAO .class);
_serviceLogicUT.setServiceDAO(_serviceDAOMock);
String input = "Some input";
//some other method calls -> .execute(...).andReturn(...);
Capture<ComplexParam> capturedParam = new Capture<ComplexParam>();
_serviceDaoMock.executeStatement(EasyMock.capture(capturedParam)); // assuming a void method
EasyMock.replay(_serviceDaoMock);
// run
_serviceLogicUT.getDataFrom(input);
ComplexParam actualParam = capturedParam.getValue();
// make various assertions on actual param
}
}
I think you can see from the two examples why many people prefer Mockito, but if there's some reason you prefer or are mandated to use EasyMock, you can do just about anything you can do with Mockito, just with more lines of code.
This should be possible with jmockit, unless you DAO has final methods. However, this is better and easier done with jMockit:
#Test
public void testMethod(#Mocked final ServiceDAO serviceDAO) {
new Expectations() {{
serviceDAO.executeStatement(expectedOParams);returns(expectedReturnValue)
}};
(new ServiceLogic(serviceDAO)).getData();
}
That's almost complete test save assertions. And it works with final, static, abstract and whatever methods.
OK, so the #Ignore annotation is good for marking that a test case shouldn't be run.
However, sometimes I want to ignore a test based on runtime information. An example might be if I have a concurrency test that needs to be run on a machine with a certain number of cores. If this test were run on a uniprocessor machine, I don't think it would be correct to just pass the test (since it hasn't been run), and it certainly wouldn't be right to fail the test and break the build.
So I want to be able to ignore tests at runtime, as this seems like the right outcome (since the test framework will allow the build to pass but record that the tests weren't run). I'm fairly sure that the annotation won't give me this flexibility, and suspect that I'll need to manually create the test suite for the class in question. However, the documentation doesn't mention anything about this and looking through the API it's also not clear how this would be done programmatically (i.e. how do I programatically create an instance of Test or similar that is equivalent to that created by the #Ignore annotation?).
If anyone has done something similar in the past, or has a bright idea of how else I could go about this, I'd be happy to hear about it.
The JUnit way is to do this at run-time is org.junit.Assume.
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
// rest of setup.
}
You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization.
An assumption failure causes the test to be ignored.
Edit: To compare with the #RunIf annotation from junit-ext, their sample code would look like this:
#Test
public void calculateTotalSalary() {
assumeThat(Database.connect(), is(notNull()));
//test code below.
}
Not to mention that it is much easier to capture and use the connection from the Database.connect() method this way.
You should checkout Junit-ext project. They have RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
[Code sample taken from their tutorial]
In JUnit 4, another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}
Additionally to the answer of #tkruse and #Yishai:
I do this way to conditionally skip test methods especially for Parameterized tests, if a test method should only run for some test data records.
public class MyTest {
// get current test method
#Rule public TestName testName = new TestName();
#Before
public void setUp() {
org.junit.Assume.assumeTrue(new Function<String, Boolean>() {
#Override
public Boolean apply(String testMethod) {
if (testMethod.startsWith("testMyMethod")) {
return <some condition>;
}
return true;
}
}.apply(testName.getMethodName()));
... continue setup ...
}
}
A quick note: Assume.assumeTrue(condition) ignores rest of the steps but passes the test.
To fail the test, use org.junit.Assert.fail() inside the conditional statement. Works same like Assume.assumeTrue() but fails the test.