Package ch.panter.jmock.gettingstarted

Source Code of ch.panter.jmock.gettingstarted.PublisherTest

/**
*
*/
package ch.panter.jmock.gettingstarted;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import junit.framework.Assert;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.Sequence;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import ch.panter.jmock.gettingstarted.IPublisher;
import ch.panter.jmock.gettingstarted.ISubscriber;
import ch.panter.jmock.gettingstarted.PublisherImpl;

/**
* Demonstration of some fuctions of the jmock library.
* <p>
* Have a look at
* <a href="http://www.jmock.org/cookbook.html"> the
* jmock cookbook</a> for a lot more examples.
* </p>
*
* @author bseelige
*
*/
@RunWith(JMock.class)
public class PublisherTest {
   
   
    /** jmock context */
    Mockery context;
    /** instance under test */
    IPublisher instance;
   
    @Before
    public void setUp() {
        context = new JUnit4Mockery();
        instance = new PublisherImpl();
    }
   
    /**
     * In an outline, a jmock 2 test looks like
     * the following.
     */
    @Test
    public void jmockTemplate() {
        // set up
        // ... set up code ...
                 
        // define expectations
        context.checking(new Expectations() {{
            // ... expectations go here ...
           
            // An expectations block can contain any number
            // of expectations. Each expectation has the
            // following structure:
            /*
            invocation-count (mock-object).method(argument-constraints);
            inSequence(sequence-name);
            when(state-machine.is(state-name));
            will(action);
            then(state-machine.is(new-state-name));
            */
            // Except for the invocation count and the mock
            // object, all clauses are optional. You can give
            // an expectation as many inSequence, when, will
            // and then clauses as you wish.
        }});
       
        // execute
        // ... code being tested ...
       
        // after execution junit assertations
        // ... assertions ...
    }
   
    /**
     * Creates a simple mock for the ISubscriber interface.
     * <p>
     * After the code under test has finished our test must
     * verify that the mock Subscriber was called as expected.
     * If the expected calls were not made, the test will fail.
     * The MockObjectTestCase does this automatically. You
     * don't have to explicitly verify the mock objects
     * in your tests. The JMock test runner does this
     * automatically. You don't have to explicitly verify
     * the mock objects in your tests.
     * </p>
     *
     */
    @Test
    public void oneSubscriberReceivesAMessage() {
        // set up
        final ISubscriber subscriber = context.mock(ISubscriber.class);
        instance.add(subscriber);
        final String message = "message";
       
        // expectations
        // first bracet creates an anonymous inner class
        // second braced is the static initializer of the class
        context.checking(new Expectations() {{
            // one and all the other invocation count methods
            // return an instance of the same class as it's
            // argument
            one (subscriber).receive("message");
        }});
       
        // execute
        instance.publish(message);
    }
   
    /**
     * Sequences are used to define expectations that must
     * occur in the order in which they appear in the test
     * code. A test can create more than one sequence and an
     * expectation can be part of more than once sequence
     * at a time.
     */
    @Test
    public void oneSubscriberReceivesASequnce() {
        // set up
        final ISubscriber subscriber = context.mock(ISubscriber.class);
        instance.add(subscriber);
       
        final Sequence seq = context.sequence("msgseq");
        // double braces again, see
        // http://www.c2.com/cgi/wiki?DoubleBraceInitialization
        final List<String> messages = new ArrayList<String>()
        {{
            add("message1"); add("message2"); add("message3");
        }};
       
        // expectations
        // first bracet creates an anonymous inner class
        // second braced is the static initializer of the class
        context.checking(new Expectations() {{
            // one and all the other invocation count methods
            // return an instance of the same class as it's
            // argument
            one (subscriber).receive(messages.get(0));
            inSequence(seq);
            one (subscriber).receive(messages.get(1));
            inSequence(seq);
            one (subscriber).receive(messages.get(2));
            inSequence(seq);
        }});
       
        // execute
        for (String message : messages) {
            instance.publish(message);
        }
    }
   
    /**
     * The "invocation count" of an expectation defines the
     * minimum and maximum number of times that the expected
     * method is allowed to be invoked. It is specified before
     * the mock object in the expectation.
     *
     * <ul>
     * <li>one: The invocation is expected once and once only.</li>
     * <li>exactly(n).of: The invocation is expected exactly n times.</li>
     * <li>atLeast(n).of: The invocation is expected at least n times.</li>
     * <li>atMost(n).of: The invocation is expected at most n times.</li>
     * <li>between(min, max).of: The invocation is expected at least min times and at most max times.</li>
     * <li>allowing: The invocation is allowed any number of times but does not have to happen.</li>
     * <li>ignoring: The same as allowing. Allowing or ignoring should be chosen to make the test code clearly express intent.</li>
     * <li>never: The invocation is not expected at all. This is used to make tests more explicit and so easier to understand.</li>
     * </ul>
     *
     */
    @Test
    public void expectingMoreThanOnce() {
        // set up
        final ISubscriber subscriber = context.mock(ISubscriber.class);
        instance.add(subscriber);
       
        final String message = "message";
       
        // expectations
        context.checking(new Expectations() {{
            // one and all the other invocation count methods
            // return an instance of the same class as it's
            // argument
            exactly(10).of (subscriber).receive(message);
           
            //some alternatives:
            //allowing (subscriber).receive(message);
            //atLeast(5).of (subscriber).receive(message);
            //between(5, 15).of (subscriber).receive(message);
            //never (subscriber).receive(message);
        }});
       
        // execute
        for (int i = 0; i<10 ; i++) {
            instance.publish(message);  
        }
    }
   
    /**
     * Most of the time expectations specify literal parameter
     * values that are compared for equality against the
     * actual parameters of invoked methods (see above).
     * <p>
     * Sometimes, however, you will need to define looser
     * constraints over parameter values to clearly express
     * the intent of the test or to ignore parameters (or
     * parts of parameters) that are not relevant to the
     * behaviour being tested
     * </p>
     * <p>
     * Loose parameter constraints are defined by specifying
     * matchers  for each parameter. Matchers are created by
     * factory methods, such as lessThan, equal and
     * stringContaining in the example above, to ensure
     * that the expectation is easy to read. The result
     * of each factory method must be wrapped by a call to
     * the with method.
     * </p>
     * <p>
     * Matchers can be combined to tighten or loosen the
     * specification if necessary. The set of matchers
     * is extensible1 so you can write new matchers to
     * cover unusual testing scenario.
     * </p>
     * @see<a href="http://www.jmock.org/custom-matchers.html">
     * "http://www.jmock.org/custom-matchers.html"</a>
     */
    @Test
    public void usingMatchers() {
        // set up
        final ISubscriber subscriber = context.mock(ISubscriber.class);
        instance.add(subscriber);
       
        final String message = "message";
       
        // expectations
        context.checking(new Expectations() {{
            // test for exact match
            one (subscriber).receive(message);
            // alternative test for exact match
            one (subscriber).receive(with(equal(message)));
            // test for object identity
            one (subscriber).receive(with(same(message)));
            // test for not null
            one (subscriber).receive(with(aNonNull(String.class)));
            // "ignoring" the parameter
            one (subscriber).receive(with(any(String.class)));
            // combined matcher
            one (subscriber).receive(with(not(aNull(String.class))));
            // these are Hamcrest matchers, see
            // http://code.google.com/p/hamcrest/wiki/Tutorial
            // test for substring
            one (subscriber).receive(with(containsString("mess")));

        }});
       
       
        // execute
        for (int i=0; i<7; i++) {
            instance.publish(message);
        }
    }
}
TOP

Related Classes of ch.panter.jmock.gettingstarted.PublisherTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.