JMock assertIsSatisfied in TearDown? - java

I don't know why, but I have always written my JMock tests like this:
#Test
public void testMyThing() throws Exception {
mockery.checking(new Expectations() {{
oneOf(mockObj).foo();
}});
testObj.bar(); // calls mockObj.foo()
mockery.assertIsSatisfied();
}
But when there are many tests, is it better to move assertIsSatisfied to the tear-down?
#After
public void tearDown() throws Exception {
mockery.assertIsSatisfied();
}

The recommended way to do this is to use the JMock runner. Annotate the class with
#RunWith(JMock.class)
public class TestClass {
This will call the assertion at the right place in the test lifecycle. Teardown isn't the right place as a failure might not be reported in correctly and might mess up other cleanup.
We also have a mockery rule in the repository that works with the new #Rule infrastructure.

Yes, I tend to do it in teardown. It keeps the focus of the individual test methods on what they're actually testing, by removing the boilerplate out into the #After- it's critical to me that tests are as expressive and readable as possible.
In fact, I sometimes take it further than that, and use a JMockSupport base class that handles the Mockery for me (as well as providing convenience implementations of mock(...)). This is just a convenience, of course, and by no means a requirement like it was in JUnit 3.

Related

Junit - method at the end of each test

I got a method that I call at the end of every test to reset the streams positions.
Test{
[....]
reset();
}
Is there any elegant way to avoid such a repetition?
Try #After annotaton, that goes with JUnit.
Example from source:
public class Example {
File output;
#Before public void createOutputFile() {
output= new File(...);
}
#Test public void something() {
...
}
#After public void deleteOutputFile() {
output.delete();
}
}
the other answers suggest the #After annotation on a public method (preferably with name teardown) which is technically right and a good answer to your question.
But essential properties of unittests is that they need to be fast and independent of each other.
Therefore the better approach is to use a fresh mock of the stream with every test. This is best done by using a mocking framework like Mockito, JMock or alike.
Yes, create new method with #After annotation.
You should use the #After annotation - indicates something needs to be done at the end of each method run.
Use #After annotation.
#Test
public void testSomething() {
// test goes here
}
#After
public void doSomethingAfterTest() {
// reset
}
As others have pointed out, there are the #s: Before and After. Class instance methods with these annotations will run before/after every test case.
There is also BeforeClass and AfterClass, which I didn't see anyone point out yet. These #s may be put onto static methods of your class, and those methods will execute before and after all of the tests in your class have completed. It is handy in certain situations.

Is It Possible to Override an Expected Exception in JUnit?

I recently found out that JUnit > 4.10 allows the usage of #Rule and ExpectedException. Since I'm not big on duplicating code I tried the following. For a better understanding I scaled it down from several tests to just these two. The MockitoJUnitRunner is intentional although it's not used in the small scaled example.
pom.xml
<dependencies>
<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
</dependencies>
TestBase
#RunWith(MockitoJUnitRunner.class)
public class TestBase {
/** JUnit > 4.10 allows expected exception handling like this */
#Rule
public ExpectedException exception = ExpectedException.none();
#Before
public void setup() {
this.expectBadParam();
}
protected void expectBadParam() {
this.exception.expect(NullPointerException.class);
}
}
The problem is that the following test is not working as I would expect it to. What I'm trying is by default expect an exception type and in some cases run a normal JUnit test. I can't reset the expected exception once it's set.
public class ExpectedExceptionTest extends TestBase {
#Test
public void error() {
throw new NullPointerException();
}
#Test
public void success() {
this.exception = ExpectedException.none();
// this should be a success
}
}
I already found a different solution by duplicating the expectBadParam method in each method I expect an exception as well as overriding the #Before annotation in the test class. However I'm hoping someone can help me understand why this is not working?
The reason it's not working as you expect (no pun intended) is related to how TestRules work with JUnit.
Effectively what happens is that the test framework inspects the test case for TestRule instances, and then calls the TestRule.apply() method on each on in turn. This method takes a Statement object and returns a Statement(). Your test case object is initially wrapped in a Statement, given to the first TestRule, which returns a brand new Statement wrapping the original Statement. So, basically, the TestRule is being given the opportunity to adapt the original TestCase, generally adding new functionality. Once the framework has gone through all the TestRule instances it calls the Statement.evaluate() method, like it would do for any 'standard' test case it builds up which doesn't have any TestRules attached to it.
The key thing here is that all the interaction between the framework and the TestRule instances happens at test case construction time. Once the test case has been built up, the fields containing the rules are no longer queried or directly interacted with by the test framework. Their main purpose afterwards is for tests to interact with the mutable state contained within the rules. So, if you change the instance field as you do in your test case success() you'll have absolutely no effect on the outcome of the rules, because the rule expecting an IllegalArgumentException has already been applied to the test case.
There's a 'typical' shape to a TestRule implementation. They look like this...
public void apply(Statement base, Description description) {
return new Statement() {
public void evaluate( ) {
// some initialisation
try {
base.evaluate();
} finally {
// some tidy up here
}
}
}
}
Here the TestRule gets an opportunity to run some code after the test case has completed. This is how ExpectedException works (although it has a 'catch Exception(e)' block also). During the course of the test you can call methods on the rule instance which builds up state within the TestRule object which is then used when the finally block is called. So, when you call 'exception.expect(IllegalArgumentException.class)`, the test rule stores a matcher in a list and basically matches caught exceptions using that matcher and any others you may have set up. When you reset the instance field in your test case all that state in the original instance is still there and so the test still fails.
To do what you want to do you need a means of resetting the internal state of the ExpectedException instance. Unfortunately, there are no methods on the ExpectedException class which allow you to remove expectations which have been added. It's only really possible to add expectations. And, to be honest, this is for a good reason - your tests should be logically grouped, with finer grained details being added the closer you get to the test case. The act of 'resetting' expectations is an act of removing rather than adding a detail and so suggests that your tests are not logically grouped well enough. It creates maintainability difficulties if some part of a test suite adds some expectations and another part removes some / all of them.
You have 2 options if you want to use ExpectedException here. The first is to split your test class, or test base class, in two. One suite should be for tests which expect the IllegalArgumentException and another for ones which don't or which have some kind of alternative exception they expect. The second is to accept the duplication inherent in having 44 tests which have to explicitly declare they expect an exception and only 4 tests which don't.
It's possible you may be able to achieve what you want with JUnit Theories in some way, although that would depend very much on how your test cases work.
The solution is to Override the setup method,
You could also do it manually:
#Test
public void success() {
try{
... all your code
} catch (Exception e){
// check your nested clauses
if(e.getCause() instanceof ExpectedException){
// pass
} else {
Assert.fail("unexpected exception");
}
}
Please find bellow interesting links to learn more about :
testing-custom-exceptions-w-junits
Code showing how to test a custom exception by using a Hamcrest
Matcher
Good luck :)

Non static #BeforeClass equivalent when Spring unit test runner? [duplicate]

Are there any best practices to get Junit execute a function once in a test file , and it should also not be static.
like #BeforeClass on non static function?
Here is an ugly solution :
#Before void init(){
if (init.get() == false){
init.set(true);
// do once block
}
}
well this is something i dont want to do , and i am looking for an integrated junit solution.
A simple if statement seems to work pretty well too:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {
public static boolean dbInit = false;
#Autowired
DbUtils dbUtils;
#Before
public void setUp(){
if(!dbInit){
dbUtils.dropTables();
dbUtils.createTables();
dbInit = true;
}
}
...
To use an empty constructor is the easiest solution. You can still override the constructor in the extended class.
But it's not optimal with all the inheritance. That's why JUnit 4 uses annotations instead.
Another option is to create a helper method in a factory/util class and let that method do the work.
If you're using Spring, you should consider using the #TestExecutionListeners annotation.
Something like this test:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({CustomTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
#ContextConfiguration("test-config.xml")
public class DemoTest {
Spring's AbstractTestExecutionListener contains for example this empty method that you can override:
public void beforeTestClass(TestContext testContext) throws Exception {
/* no-op */
}
NOTE: DO NOT overlook/miss DependencyInjectionTestExecutionListener while adding custom TestExecutionListeners. If you do, all the autowires will be null.
If you don't want to set up static initializers for one time initialization and are not particular about using JUnit, take a look at TestNG. TestNG supports non-static, one-time initialization with a variety of configuration options, all using annotations.
In TestNG, this would be equivalent to:
#org.testng.annotations.BeforeClass
public void setUpOnce() {
// One time initialization.
}
For teardown,
#org.testng.annotations.AfterClass
public void tearDownOnce() {
// One time tear down.
}
For the TestNG equivalent of JUnit 4's #Before and #After, you can use #BeforeMethod and #AfterMethod respectively.
Easily use #BeforeAllMethods/#AfterAllMethods annotations to run a method inside the instance context (non-static), where all injected values will be available.
There is a special testing library for this:
https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0
https://bitbucket.org/radistao/before-after-spring-test-runner/
The only limitation: works only for Spring testing.
(I'm the developer of this testing library)
I've never tried but maybe you can create a no-argument constructor and call you function from there?
The article discuss 2 very nice solutions for this problem:
"clean" junit with custom Runner (using interface but you could extend it with a custom annotation e.g. #BeforeInstance)
Spring execution listeners as mentioned by Espen before.
UPDATE: Please see the comment by Cherry for why the suggestion below is flawed. (Am keeping the answer on here rather than deleting as the comment may provide useful information to others as to why this doesn't work.)
Another option worth considering if using dependency injection (e.g. Spring) is #PostConstruct. This will guarantee dependency injection is complete, which wouldn't be the case in a constructor:
#PostConstruct
public void init() {
// One-time initialization...
}
Just use #BeforeClass:
#BeforeClass
public static void init() {
}
It doesn't make sense for init to be non-static because each test is run in a separate instance. The instance
that init is run on would not match the instance of any test.
The only reason that you might want it to be non-static is to override it in subclasses, but you can do this
with static methods too. Just use the same name, and only the subclass init method will be called.

How to write unit test by mocking, when you have zero arg:constructors

I was trying to write unit test using jmocks and junit. (My Project uses core java- no frameworks-) I could not write unit test for some of my classes, by mocking external dependencies, when dependencies were initialized in a a no arg-constructor.
As i cannot provide the actual code, trying to explain the scenario by an example
public interface Apple {
String variety();
}
Implementation.
public class MalgovaApple implements Apple {
#Override
public String variety() {
return "Malgova";
}
}
Class to be tested
public class VarietyChecker {
private Apple apple;
VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}
public String printAppleVariety(){
String variety = apple.variety();
if(variety.length() < 3){
System.out.println("Donot use Code names- Use complete names");
return "bad";
}
return "good";
}
}
Junit test using jmock
public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test_VarietyChecker() throws Exception{
final Apple mockapple = context.mock(Apple.class);
VarietyChecker printer = new VarietyChecker();
context.checking(new Expectations(){{
oneOf(mockapple).variety();will(returnValue("as"));
}});
String varietyNameValid = printer.printAppleVariety();
assertEquals("bad",varietyNameValid);
} }
This test fails - Mocking does not work the values "as" is not injected, the test class executes with MalgovaApple ...
Now if we add below constructor to VarietyChecker and use it test case - it gives expected output...
public VarietyChecker(Apple apple) {
super();
this.apple = apple;
}
and in unit test create test class object like
VarietyChecker printer = new VarietyChecker(mockapple);
Exposing a new constructor just for the purpose of testing is not a good idea. After all it is said that you should not alter the code for testing alone, more than that, i am afraid we have already written "some"(amount) code...
Am i missing something in junit or jmock that can make mocking work even incase of no-arg constructors. Or is this a limitation of simple junit and jmocks and should i migrate to something powerful like Jmockit /PowerMock
You should consider two choices.
Use a constructor parameter as you describe.
In this case, you're not "exposing a new constructor just for the purpose of testing". You're making your class more flexible by allowing callers to use a different factory implementation.
Don't mock it.
In this case, you are declaring that it never makes sense to use a different factory. Sometimes this is okay. At that point, the question changes, though. Instead of, "How do I mock this?" your question is now, "What am I gaining from writing this test?" You might not be gaining much of anything, and it might not make much sense to write the test at all.
If you don't mock it and decide a unit test is still worth it, then you should be asserting on other aspects of the code. Either an end state or some output. In this case, the factory call becomes an implementation detail that's not appropriate for mocking.
It's important not to fall for a "unit test everything" mentality. That is a recipe for Test-induced Design Damage. Evaluate your tests on a case by case basis, deciding whether they're providing you any real value or not. Not writing a unit test is a valid option and is even appropriate at times, even if it's option you try very hard to avoid.
Only you can make a determination which one makes the most sense in this case. From the the fact that this is a factory object we're talking about, I'd probably lean toward the former.

Declaring Jmockit mock parameters on #BeforeMethod of TestNG

I've been testing my code behavior using TestNG and JMockit for a while now and I have had no specific issue with their combination. Today I came across a situation where I needed to mock one of my internal dependencies, in the so called, type wide manner and I did not need to keep that mock around since none of the test cases dealt with it directly while they counted on the mocked version functionality. So, naturally, I put the mocking logic in my #BeforeMethod. Here is a sample:
public class SampleTest
{
#Mocked
#Cascading
private InnerDependency dependency;
#BeforeMethod
public void beforeMethod()
{
new NonStrictExpectations()
{
{
dependency.getOutputStream((String)any);
result = new Delegate<OutputStream>()
{
public OutputStream getOutputStream(String url)
{
return null;
}
};
}
};
}
#Test
public void testNormalOperation()
{
// The test whose desired behavior depends on dependency being mocked out
// ..
}
}
But, since my tests do not care about the mocked dependency explicitly, I'm not willing to declare it as a test class field, unlike what is done above. To my knowledge of JMockit The only options remaining would be:
Declare dependency as a local mock field:
new NonStrictExpectations()
{
#Cascading
private InnerDependency dependency;
{
//...
}
}
Declare dependency as an input argument for beforeMethod(), similar to what is done for normal #Test methods:
#BeforeMethod
public void beforeMethod(#Mocked #Cascading final InnerDependency dependency)
{
// ...
}
I see that JMockit 1.6+ would not like the first option and warns with WARNING: Local mock field "dependency" should be moved to the test class or converted to a parameter of the test method. Hence, to keep everyone happy, I'm ruling this option out.
But for the second option, TestNG (currently 6.8.6) throws exception when running the test saying java.lang.IllegalArgumentException: wrong number of arguments. I don't see this behavior with normal #Test cases passed with #Mocked parameters. Even playing with #Parameter and #Optional will not help (and should not have!).
So, is there any way I could make this work without declaring the unneccessary test class mock field, or am I missing something here?
Thanks
Only test methods (annotated with #Test in JUnit or TestNG) support mock parameters, so the only choice here is to declare a mock field at the test class level.
Even if not used in any test method, I think it's better than having it declared in a setup method (using #Before, #BeforeMethod, etc.). If it were to be possible, the mock would still have to apply to all tests, because of the nature of setup methods; having a mock field of the test class makes it clear what the scope of the mock is.
Dynamic partial mocking is one more technique to specify #Mocked dependencies locally. However, it has it's limitations (see comments below).

Categories