Parameterized Tests in JUnit 4.x

Parameterized tests is one of the features that have come along in the JUnit 4.x releases that I don’t find myself using very often but when I do, I find tremendously useful. In a nutshell, parameterized tests allow you to run the same test over and over again using different values. I’ve found this approach very useful when you are testing a function and have a table of data defining the input value(s) and the expected result. That being said, parameterized tests can be used for testing more than just pure “functions.”

This post walks through a detailed example of using JUnit’s parameterized tests.

The Scenaio Under Test: Boxing the Compass

The example I’m going to use is that of turning a compass bearing in degrees into a directional compass point. I’m definitely not an expert in cartography or navigation techniques so if you happen to be one, please let me know if I’ve made any mistakes in the terminology.

Client code will want to provide a bearing in degrees and the number of directional points on the compass (see the Wikipedia articles on Boxing the Compass and Compass Rose if you are interested in a better description of this) and get back the compass point of that bearing. In other words, if you have a bearing of 65.23 degrees and an eight-point compass rose, that corresponds to a compass point of Northeast. In code, this looks like (using JUnit/Hamcrest):

assertThat(CompassPoint.fromBearing(65.32, CompassRose.EIGHT_POINT), is(CompassPoint.NE));
 
assertThat(CompassPoint.fromBearing(343, CompassRose.EIGHT_POINT), is(CompassPoint.N));
assertThat(CompassPoint.fromBearing(343, CompassRose.SIXTEEN_POINT), is(CompassPoint.NNW));

As I begin implementing the code to solve this problem, all I have is the table of compass points on the Boxing the Compass page. I don’t know what the actual algorithm is that I will be using. Since I have a table of data describing the desired and a function that I need to implement, JUnit’s parameterized tests seem like a good choice to help me use TDD to drive out the algorithm’s implementation.

To start out, I created the shell of the CompassPoint and CompassRose. I’ve chosen to use enums for the implementation. That implementation detail isn’t important for this example, but in retrospect, it somewhat interesting on its own as it ends up roughly being a form of the strategy pattern using enums, albeit a tightly couple one. Also for the example, I’m only showing eight and sixteen-point data to save space as the additional data points for four and 32-point don’t add anything to the example. The code we will create will work with four and 32-point compass roses as well.

Enough of the background. Here is the shell of the code we start with.

public enum CompassPoint {
 
	N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW;
 
	public enum CompassRose {
 
		EIGHT_POINT(8), SIXTEEN_POINT(16);
 
		private int points;
 
		private CompassRose(int points) {
			this.points = points;
		}
	}
 
	public String abbreviation() {
		return name();
	}
 
	public static CompassPoint fromBearing(double bearing,
			CompassRose compassRose) {
		// TODO This is the algorithm we want to implement
		return null;
	}
}

Defining the Parameterized Test

TestNG is the framework that made parameterized tests popular to the mainstream, or if not the mainstream at least to me. JUnit added their own JUnit’s parameterized testing capabilities in version 4, which at this point has been around for a while. Implementing parameterized tests is relatively straightforward but they are definitely more involved than writing a simple test case. There are five components, or steps, that you need to consider.

  • Annotate your test class with @RunWith(Parameterized.class)
  • Create a public static method annotated with @Parameters that returns a Collection of Objects that make up your test data set.
  • Create a public constructor that takes in what is equivalent to one “row” of your test data.
  • Create an instance variable for each “column” of test data.
  • Create your tests case(s) as you normally would using the instance variables as the source of the test data. The test case will be invoked once per each row of data.

I’ll step through each one of these with our concrete example.

@RunWith(Parameterized.class)

Parameterized is a custom JUnit Runner. Simply add the @RunWith(Parameterized.class) annotation to your test class to have JUnit run it as a parameterized test.

@RunWith(Parameterized.class)
public class CompassPointTest {

@Parameters Method

When your test class has the @RunWith(Parameterized.class) annotation, JUnit will looks for a public static method annotated with @Parameter. As I mentioned above, think of this method as returning your test data set. The method must have a return type of Collection<. If you think of your test data as a table of values, each element in the Collection is a row and each index in the Object array is a column.

For our example, I copied the table at Boxing the Compass into a spreadsheet and manipulated it to get it into the format needed by JUnit. The result is.

 
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] { //
                { SIXTEEN_POINT, 0, N }, // center
                        { SIXTEEN_POINT, 11.24, N }, // high
                        { SIXTEEN_POINT, 11.25, NNE }, // low
                        { SIXTEEN_POINT, 22.5, NNE }, // center
                        { SIXTEEN_POINT, 33.74, NNE }, // high
                        { SIXTEEN_POINT, 33.75, NE }, // low
                        { SIXTEEN_POINT, 45, NE }, // center
                        { SIXTEEN_POINT, 56.24, NE }, // high
                        { SIXTEEN_POINT, 56.25, ENE }, // low
                        { SIXTEEN_POINT, 67.5, ENE }, // center
                        { SIXTEEN_POINT, 78.74, ENE }, // high
                        { SIXTEEN_POINT, 78.75, E }, // low
                        { SIXTEEN_POINT, 90, E }, // center
                        { SIXTEEN_POINT, 101.24, E }, // high
                        { SIXTEEN_POINT, 101.25, ESE },// low
                        { SIXTEEN_POINT, 112.5, ESE },// center
                        { SIXTEEN_POINT, 123.74, ESE },// high
                        { SIXTEEN_POINT, 123.75, SE }, // low
                        { SIXTEEN_POINT, 135, SE }, // center
                        { SIXTEEN_POINT, 146.24, SE }, // high
                        { SIXTEEN_POINT, 146.25, SSE }, // low
                        { SIXTEEN_POINT, 157.5, SSE }, // center
                        { SIXTEEN_POINT, 168.74, SSE }, // high
                        { SIXTEEN_POINT, 168.75, S }, // low
                        { SIXTEEN_POINT, 180, S }, // center
                        { SIXTEEN_POINT, 191.24, S }, // high
                        { SIXTEEN_POINT, 191.25, SSW }, // low
                        { SIXTEEN_POINT, 202.5, SSW }, // center
                        { SIXTEEN_POINT, 213.74, SSW }, // high
                        { SIXTEEN_POINT, 213.75, SW }, // low
                        { SIXTEEN_POINT, 225, SW }, // center
                        { SIXTEEN_POINT, 236.24, SW }, // high
                        { SIXTEEN_POINT, 236.25, WSW }, // low
                        { SIXTEEN_POINT, 247.5, WSW }, // center
                        { SIXTEEN_POINT, 258.74, WSW }, // high
                        { SIXTEEN_POINT, 258.75, W }, // low
                        { SIXTEEN_POINT, 270, W }, // center
                        { SIXTEEN_POINT, 281.24, W }, // high
                        { SIXTEEN_POINT, 281.25, WNW }, // low
                        { SIXTEEN_POINT, 292.5, WNW }, // center
                        { SIXTEEN_POINT, 303.74, WNW }, // high
                        { SIXTEEN_POINT, 303.75, NW }, // low
                        { SIXTEEN_POINT, 315, NW }, // center
                        { SIXTEEN_POINT, 326.24, NW }, // high
                        { SIXTEEN_POINT, 326.25, NNW }, // low
                        { SIXTEEN_POINT, 337.5, NNW }, // center
                        { SIXTEEN_POINT, 348.74, NNW }, // high
                        { SIXTEEN_POINT, 348.75, N }, // low
                        { SIXTEEN_POINT, 360, N }, // center
 
                        { EIGHT_POINT, 0, N }, // center
                        { EIGHT_POINT, 22.4, N }, // high
                        { EIGHT_POINT, 22.5, NE }, // low
                        { EIGHT_POINT, 45, NE }, // center
                        { EIGHT_POINT, 67.4, NE }, // high
                        { EIGHT_POINT, 67.5, E }, // low
                        { EIGHT_POINT, 90, E }, // center
                        { EIGHT_POINT, 112.4, E }, // high
                        { EIGHT_POINT, 112.5, SE }, // low
                        { EIGHT_POINT, 135, SE }, // center
                        { EIGHT_POINT, 157.4, SE }, // high
                        { EIGHT_POINT, 157.5, S }, // low
                        { EIGHT_POINT, 180, S }, // center
                        { EIGHT_POINT, 202.4, S }, // high
                        { EIGHT_POINT, 202.5, SW }, // low
                        { EIGHT_POINT, 225, SW }, // center
                        { EIGHT_POINT, 247.4, SW }, // high
                        { EIGHT_POINT, 247.5, W }, // low
                        { EIGHT_POINT, 270, W }, // center
                        { EIGHT_POINT, 292.4, W }, // high
                        { EIGHT_POINT, 292.5, NW }, // low
                        { EIGHT_POINT, 315, NW }, // center
                        { EIGHT_POINT, 337.4, NW }, // high
                        { EIGHT_POINT, 337.5, N }, // "low"
                        { EIGHT_POINT, 60, N }, // center
                });
    }

Each row is data for a single test case. For example, the first row maps to the case "on a 16 point compass rose, 0 maps to North."

The elements in each individual Object array will map the the parameters to the test's constructor. I'll explain that next.

Constructor and Instance Variables

For each element the the Collection returned by our @Parameters, JUnit will instantiate a new test class and call the constructor using the value or values in that element. In our case, each element contains an array of Objects but the framework is flexible so a single String or int works equally as well.

Take an example row in our test data: { SIXTEEN_POINT, 56.24, NE }. The first column is an input CompassRose value. The second column is the input bearing in degrees. And the third column is the expected output Compass point. Our constructor take these values and stores them in corresponding instance variables that the test will access when it executes.

    private CompassRose compassRose;
    private double degrees;
    private CompassPoint expectedCompassPoint;
 
    public CompassPointTest(CompassRose compassRose, double degrees,
            CompassPoint expectedCompassPoint) {
        this.compassRose = compassRose;
        this.degrees = degrees;
        this.expectedCompassPoint = expectedCompassPoint;
    }

The Test Case

We finally arrive at our test case. The test case definition is no different than your standard JUnit test case. This test will be executed once for each element in your data set. The values that drive the test case are the instance variables populated via the constructor that JUnit calls.

    @Test
    public void compassDirectionShouldMatchDegrees() {
        CompassPoint point = CompassPoint.fromBearing(degrees, compassRose);
        assertThat(point, is(expectedCompassPoint));
    }

During the first execution of this test method, compassRose = SIXTEEN_POINT, degrees = 0, and expectedCompassPoint = N given the data supplied by the method with the @Parameters annotation.

On a side note, you can make the error messages provide additional information about what the actual data was that cause the test to fail. When the example above fails, the default JUnit output looks like the following.

java.lang.AssertionError:
Expected: is <N>
     got: <NE>

	at org.junit.Assert.assertThat(Assert.java:778)
        ....

Notice that you don't know what data actually cause the test to fail. You can leverage the description that can be provided to the assertThat (or any other) assertion method to enhance the message.

    @Test
    public void compassDirectionShouldMatchDegrees() {
        CompassPoint point = CompassPoint.fromBearing(degrees, compassRose);
        assertThat(describeExpectation(), point, is(expectedCompassPoint));
    }
 
    private String describeExpectation() {
        return "On a(n) " + compassRose + " compass rose, " + degrees
                + " degrees should translate to " + expectedCompassPoint;
    }

Now the error message has more context on the data that caused the failure.

java.lang.AssertionError: On a(n) EIGHT_POINT compass rose, 60.0 degrees should translate to N
Expected: is <N>
     got: <NE>

	at org.junit.Assert.assertThat(Assert.java:778)
       ...

The Entire Test

Here is the entire test class for reference.

package com.davidehringer.geo;
 
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static com.davidehringer.geo.CompassPoint.CompassRose.*;
import static com.davidehringer.geo.CompassPoint.*;
 
import java.util.Arrays;
import java.util.Collection;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
 
import com.davidehringer.geo.CompassPoint.CompassRose;
 
@RunWith(Parameterized.class)
public class CompassPointTest {
 
    private CompassRose compassRose;
    private double degrees;
    private CompassPoint expectedCompassPoint;
 
    public CompassPointTest(CompassRose compassRose, double degrees,
            CompassPoint expectedCompassPoint) {
        this.compassRose = compassRose;
        this.degrees = degrees;
        this.expectedCompassPoint = expectedCompassPoint;
    }
 
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] { //
                { SIXTEEN_POINT, 0, N }, // center
                        { SIXTEEN_POINT, 11.24, N }, // high
                        { SIXTEEN_POINT, 11.25, NNE }, // low
                        { SIXTEEN_POINT, 22.5, NNE }, // center
                        { SIXTEEN_POINT, 33.74, NNE }, // high
                        { SIXTEEN_POINT, 33.75, NE }, // low
                        { SIXTEEN_POINT, 45, NE }, // center
                        { SIXTEEN_POINT, 56.24, NE }, // high
                        { SIXTEEN_POINT, 56.25, ENE }, // low
                        { SIXTEEN_POINT, 67.5, ENE }, // center
                        { SIXTEEN_POINT, 78.74, ENE }, // high
                        { SIXTEEN_POINT, 78.75, E }, // low
                        { SIXTEEN_POINT, 90, E }, // center
                        { SIXTEEN_POINT, 101.24, E }, // high
                        { SIXTEEN_POINT, 101.25, ESE },// low
                        { SIXTEEN_POINT, 112.5, ESE },// center
                        { SIXTEEN_POINT, 123.74, ESE },// high
                        { SIXTEEN_POINT, 123.75, SE }, // low
                        { SIXTEEN_POINT, 135, SE }, // center
                        { SIXTEEN_POINT, 146.24, SE }, // high
                        { SIXTEEN_POINT, 146.25, SSE }, // low
                        { SIXTEEN_POINT, 157.5, SSE }, // center
                        { SIXTEEN_POINT, 168.74, SSE }, // high
                        { SIXTEEN_POINT, 168.75, S }, // low
                        { SIXTEEN_POINT, 180, S }, // center
                        { SIXTEEN_POINT, 191.24, S }, // high
                        { SIXTEEN_POINT, 191.25, SSW }, // low
                        { SIXTEEN_POINT, 202.5, SSW }, // center
                        { SIXTEEN_POINT, 213.74, SSW }, // high
                        { SIXTEEN_POINT, 213.75, SW }, // low
                        { SIXTEEN_POINT, 225, SW }, // center
                        { SIXTEEN_POINT, 236.24, SW }, // high
                        { SIXTEEN_POINT, 236.25, WSW }, // low
                        { SIXTEEN_POINT, 247.5, WSW }, // center
                        { SIXTEEN_POINT, 258.74, WSW }, // high
                        { SIXTEEN_POINT, 258.75, W }, // low
                        { SIXTEEN_POINT, 270, W }, // center
                        { SIXTEEN_POINT, 281.24, W }, // high
                        { SIXTEEN_POINT, 281.25, WNW }, // low
                        { SIXTEEN_POINT, 292.5, WNW }, // center
                        { SIXTEEN_POINT, 303.74, WNW }, // high
                        { SIXTEEN_POINT, 303.75, NW }, // low
                        { SIXTEEN_POINT, 315, NW }, // center
                        { SIXTEEN_POINT, 326.24, NW }, // high
                        { SIXTEEN_POINT, 326.25, NNW }, // low
                        { SIXTEEN_POINT, 337.5, NNW }, // center
                        { SIXTEEN_POINT, 348.74, NNW }, // high
                        { SIXTEEN_POINT, 348.75, N }, // low
                        { SIXTEEN_POINT, 360, N }, // center
 
                        { EIGHT_POINT, 0, N }, // center
                        { EIGHT_POINT, 22.4, N }, // high
                        { EIGHT_POINT, 22.5, NE }, // low
                        { EIGHT_POINT, 45, NE }, // center
                        { EIGHT_POINT, 67.4, NE }, // high
                        { EIGHT_POINT, 67.5, E }, // low
                        { EIGHT_POINT, 90, E }, // center
                        { EIGHT_POINT, 112.4, E }, // high
                        { EIGHT_POINT, 112.5, SE }, // low
                        { EIGHT_POINT, 135, SE }, // center
                        { EIGHT_POINT, 157.4, SE }, // high
                        { EIGHT_POINT, 157.5, S }, // low
                        { EIGHT_POINT, 180, S }, // center
                        { EIGHT_POINT, 202.4, S }, // high
                        { EIGHT_POINT, 202.5, SW }, // low
                        { EIGHT_POINT, 225, SW }, // center
                        { EIGHT_POINT, 247.4, SW }, // high
                        { EIGHT_POINT, 247.5, W }, // low
                        { EIGHT_POINT, 270, W }, // center
                        { EIGHT_POINT, 292.4, W }, // high
                        { EIGHT_POINT, 292.5, NW }, // low
                        { EIGHT_POINT, 315, NW }, // center
                        { EIGHT_POINT, 337.4, NW }, // high
                        { EIGHT_POINT, 337.5, N }, // "low"
                        { EIGHT_POINT, 60, N }, // center
                });
    }
 
    @Test
    public void compassDirectionShouldMatchDegrees() {
        CompassPoint point = CompassPoint.fromBearing(degrees, compassRose);
        assertThat(describeExpectation(), point, is(expectedCompassPoint));
    }
 
    private String describeExpectation() {
        return "On a(n) " + compassRose + " compass rose, " + degrees
                + " degrees should translate to " + expectedCompassPoint;
    }
}

If you run the test, you will notice that JUnit will actually execute an instance of the test for each row in your test data. Unfortunately, the name of the test will simply be the index of the element in the Collection. As far as I know the test name cannot be customized to provide better context. If you are generating specifications from your test cases, this would be highly desirable since the index number means nothing from a specification perspective. If you use Eclipse, you'll see something similar to the following.
eclipse junit 269x300 Parameterized Tests in JUnit 4.x

The Implementation

At this point, I've covered everything you need to know about parameterized tests in JUnit. But from a TDD process perspective, we still have to implement the code that will make the tests pass. I'm not going to walk through the process for figuring out the algorithm and implementing the code since that is beyond the scope of this article. But I will show you the final code since I know you are dying to know how to convert a bearing to a compass point. Thanks goes out to my brother Geoff for helping me actually get the algorithm right!

package com.davidehringer.geo;
 
import org.apache.commons.lang.Validate;
 
public enum CompassPoint {
 
    N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW;
 
    public enum CompassRose {
 
        EIGHT_POINT(8, new CompassPoint[] { N, NE, E, SE, S, SW, W, NW }), SIXTEEN_POINT(
                16, new CompassPoint[] { N, NNE, NE, ENE, E, ESE, SE, SSE, S,
                        SSW, SW, WSW, W, WNW, NW, NNW });
 
        private int points;
        private CompassPoint[] lookupTable;
 
        private CompassRose(int points, CompassPoint[] lookupTable) {
            this.points = points;
            this.lookupTable = lookupTable;
        }
 
        public CompassPoint getPoint(int index) {
            if (index >= lookupTable.length) {
                throw new IllegalArgumentException("Invalid index: " + index
                        + ". Max index is " + (lookupTable.length - 1));
            }
            return lookupTable[index];
        }
    }
 
    public String abbreviation() {
        return name();
    }
 
    public static CompassPoint fromBearing(double bearing,
            CompassRose compassRose) {
        Validate.isTrue(bearing >= 0);
        Validate.isTrue(bearing <= 360);
 
        double shift = 360.0 / compassRose.points / 2.0;
        double normalizedBearing = (bearing + shift);
 
        int index = (int) (normalizedBearing / (360.0 / compassRose.points))
                % compassRose.points;
        return compassRose.getPoint(index);
    }
}

As shown previously, for the client, it is as simple as the following snippet.

CompassPoint point = CompassPoint.fromBearing(14.65, CompassRose.EIGHT_POINT);
String abbr = point.abbreviation();
...

In Closing

While not new, JUnit's parameterized tests are a very useful tool to have in your testing toolbox.


250 Responses to “Parameterized Tests in JUnit 4.x”

  • amazon fire tv developer Says:

    amazon fire tv developer…

    Find very professional {how to make a tv channel available now and with a great ROI now!…

  • roku developer Says:

    roku developer…

    Get the top pro {amazon fire streaming available now in addition guaranteed now!…

  • linked here Says:

    linked here…

    Get lead generating chatbot advertising technology today lifetime support today only!…

  • additional resources Says:

    additional resources…

    Contract very professional content writing available now in addition properly priced now!…

  • wireless synchronized clocks Says:

    wireless synchronized clocks…

    Start using the top school clock and bell systems currently this week and available plus in stock now and reasonably priced now only!…

  • clocks large facilities Says:

    clocks large facilities…

    Procure now the top wireless pa system for schools currently this week and available plus in stock now and with professional installation now only!…

  • Arie Walburn Says:

    Good post. I learn something new and challenging on sites I stumbleupon every day. It’s always interesting to read through articles from other authors and use a little something from other sites. |

  • Katherine Calip Says:

    It’s really a great and helpful piece of info. I’m satisfied that you simply shared this helpful info with us. Please keep us informed like this. Thank you for sharing.|

  • Angie Gully Says:

    Hi there! Do you know if they make any plugins to safeguard against hackers? I’m kinda paranoid about losing everything I’ve worked hard on. Any recommendations?

  • chatbot service Says:

    chatbot service…

    Find efficient facebook chat bot development today from a professional team today only!…

  • this post Says:

    this post…

    Find lead generating facebook chatbots technology today additionally affordable today only!…

  • list marketing Says:

    list marketing…

    Find very professional search engine keywords available now in addition properly priced now!…

  • email marketing Says:

    email marketing…

    Contract very professional placement company available now in addition with a great ROI now!…

  • Anonymous Says:

    Sterling Men…

    I found a great……

  • Terence Soldano Says:

    woh I am pleased to find this website through google.

  • Wes Lessor Says:

    Hey I know this is off topic but I was wondering if you knew of any widgets I could add to my blog that automatically tweet my newest twitter updates. I’ve been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this. Please let me know if you run into anything. I truly enjoy reading your blog and I look forward to your new updates.|

  • Jesse Cianciola Says:

    Have you ever considered creating an e-book or guest authoring on other blogs? I have a blog based on the same topics you discuss and would really like to have you share some stories/information. I know my subscribers would value your work. If you’re even remotely interested, feel free to send me an e mail.|

  • visite site Says:

    visite site…

    Buy a plan for professional benefits of social selling currently taking on new clients in addition reasonably priced now!…

  • Jonathon Pickford Says:

    I constantly emailed this webpage post page to all my contacts, since if like to read it next my links will too.|

  • Detra Shatz Says:

    Thanks for finally talking about > blog_title < Liked it!|

  • metal clock mechanism Says:

    metal clock mechanism…

    Purchase here swiss aa battery clock movement kits currently on available and ready for purchase and additionally affordable for ordering today!…

  • Buck Coventry Says:

    I was reading some of your content on this internet site and I think this website is real informative ! Keep putting up.

  • Betting script software Says:

    Nice blog! Is your theme custom made or did you download it from somewhere?
    A theme like yours with a few simple adjustements would really make my blog jump out.
    Please let me know where you got your theme. Thanks

  • Lena Jana Says:

    thank you for sharing with us, I conceive this website genuinely stands out : D.

  • FCC wireless license Says:

    FCC wireless license…

    Purchase now a high quality synchronized clock system currently this week and available plus in stock now in addition with professional installation now only!…

  • best hands for clocks Says:

    best hands for clocks…

    Buy today swiss clock kits that’s on available and ready for purchase and additionally affordable for ordering today!…

  • USA Made clock movements Says:

    USA Made clock movements…

    Buy today professional clock kits that’s on available and ready to buy and additionally affordable for ordering today!…

  • Rodrick Ow Says:

    I must show my passion for your kindness in support of women who require help on this particular study. Your very own commitment to passing the message all-around turned out to be particularly important and has regularly encouraged professionals much like me to attain their endeavors. Your personal insightful advice denotes this much to me and somewhat more to my fellow workers. Thanks a lot; from each one of us.

  • Leonard Rohen Says:

    This is my first time visit at here and i am genuinely pleassant to read everthing at single place.|

  • wirelessly synchronize clocks Says:

    wirelessly synchronize clocks…

    Procure now a high quality bell systems that is this week and available plus now in stock and with professional installation now only!…

  • wireless communication systems Says:

    wireless communication systems…

    Get now the top synchronized clocks that is this week and available plus in stock and installed by professionals now only!…

  • tenant improvement contractor Says:

    tenant improvement contractor…

    Contract us here for licensed and insured prefabricated metal buildings ready for your building projects and get you up and going with the end result you are dreaming of. Let us bid your project today!…

  • Clark Haralson Says:

    Hello There. I discovered your weblog the usage of msn. This is a very smartly written article. I’ll make sure to bookmark it and return to read more of your helpful information. Thanks for the post. I’ll definitely return.|

  • clock movement Says:

    clock movement…

    Purchase here professional battery operated quartz clock movements that’s on available and ready for purchase and cheap for ordering today!…

  • Malka Bedard Says:

    I simply could not depart your site prior to suggesting that I really loved the usual info an individual provide to your visitors? Is gonna be back incessantly to investigate cross-check new posts|

  • design metal buildings Says:

    design metal buildings…

    Contract us here for licensed and insured specialized building construction ready for your building projects and get you up and going with the end result you want. Let us bid your project today!…

  • Anonymous Says:

    Melodee Stater…

    I found a great……

  • clock Inserts videos Says:

    clock Inserts videos…

    Purchase now swiss battery clock movements currently on available and ready to buy and additionally cheap for ordering today!…

  • TI construction Says:

    TI construction…

    Get in contract here for licensed and insured steel building erectors ready for your building projects and get you going with the end result you want. Let us bid your project today!…

  • Anonymous Says:

    August Witchard…

    I found a great……

  • how to build a metal building Says:

    how to build a metal building…

    Contract us here for professional and bonded metal building contractors ready for your building projects and get you up and going with the end result you are dreaming of. Let us bid your project today!…

  • clock making replacement parts Says:

    clock making replacement parts…

    Purchase now high quality clock kit parts currently on available and ready for purchase and additionally cheap for ordering today!…

  • commercial metal buildings Says:

    commercial metal buildings…

    Get in contract here for professional and bonded steel building erectors ready for your building projects and get you up and going with the end result you are dreaming of. Let us bid your project today!…

  • steel building suppliers Says:

    steel building suppliers…

    Contract us here for professional and bonded metal building erectors ready for your building projects and get you going with the end result you are dreaming of. Let us bid your project today!…

  • Latasha Meggett Says:

    Wonderful blog! I found it while searching on Yahoo News. Do you have any tips on how to get listed in Yahoo News? I’ve been trying for a while but I never seem to get there! Thank you|

  • metal clock mechanism Says:

    metal clock mechanism…

    Purchase now swiss clock mechanism kit that are on available and ready for purchase and affordable for ordering today!…

  • Britta Litaker Says:

    I believe what you said made a ton of sense. But, think on this, suppose you added a little information? I am not suggesting your content isn’t good., however what if you added a post title that makes people desire more? I mean BLOG_TITLE is kinda plain. You ought to peek at Yahoo’s home page and note how they create news titles to get viewers to open the links. You might add a video or a picture or two to grab readers interested about everything’ve got to say. Just my opinion, it would make your blog a little bit more interesting.|

  • Anonymous Says:

    Johnathan Goosey…

    I found a great……

  • Jefferey Scher Says:

    hey there and thank you for your information – I have certainly picked up anything new from right here. I did however expertise a few technical points using this web site, since I experienced to reload the website a lot of times previous to I could get it to load properly. I had been wondering if your web host is OK? Not that I’m complaining, but slow loading instances times will often affect your placement in google and could damage your high quality score if advertising and marketing with Adwords. Anyway I am adding this RSS to my email and could look out for a lot more of your respective interesting content. Make sure you update this again soon.|

  • read more Says:

    read more…

    Purchase now high quality clock inserts that are on available and ready for purchase and additionally cheap for ordering today!…

Leave a Reply