1. 程式人生 > >@RunWith(Parameterized.class)和@RunWith(SpringJUnit4ClassRunner.class)

@RunWith(Parameterized.class)和@RunWith(SpringJUnit4ClassRunner.class)

就如標題如果你既希望載入SpringContext跑整合測試,同時又希望使用JUnit的引數化方法跑基於資料的測試,該怎麼辦?@RunWith只允許你傳入一個Class型別。

下面是一個Spring官方例子告訴你怎麼實現:

/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.test.context.junit4;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

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

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import org.springframework.beans.Employee;
import org.springframework.beans.Pet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContextManager;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;

/**
 * Simple JUnit 4 based unit test which demonstrates how to use JUnit's
 * {@link Parameterized} Runner in conjunction with
 * {@link ContextConfiguration @ContextConfiguration}, the
 * {@link DependencyInjectionTestExecutionListener}, and a
 * {@link TestContextManager} to provide dependency injection to a
 * <em>parameterized test instance.
 *
 * @author Sam Brannen
 * @since 2.5
 */
@RunWith(Parameterized.class)
@ContextConfiguration
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class })
public class ParameterizedDependencyInjectionTests {

	private static final List<Employee> employees = new ArrayList();

	@Autowired
	private ApplicationContext applicationContext;

	@Autowired
	private Pet pet;

	private final String employeeBeanName;
	private final String employeeName;

	private final TestContextManager testContextManager;


	public ParameterizedDependencyInjectionTests(final String employeeBeanName, final String employeeName)
			throws Exception {
		this.testContextManager = new TestContextManager(getClass());
		this.employeeBeanName = employeeBeanName;
		this.employeeName = employeeName;
	}

	@Parameters
	public static Collection<String[]> employeeData() {
		return Arrays.asList(new String[][] { { "employee1", "John Smith" }, { "employee2", "Jane Smith" } });
	}

	@BeforeClass
	public static void clearEmployees() {
		employees.clear();
	}

	@Before
	public void injectDependencies() throws Throwable {
		this.testContextManager.prepareTestInstance(this);
	}

	@Test
	public final void verifyPetAndEmployee() {

		// Verifying dependency injection:
		assertNotNull("The pet field should have been autowired.", this.pet);

		// Verifying 'parameterized' support:
		final Employee employee = (Employee) this.applicationContext.getBean(this.employeeBeanName);
		employees.add(employee);
		assertEquals("Verifying the name of the employee configured as bean [" + this.employeeBeanName + "].",
			this.employeeName, employee.getName());
	}

	@AfterClass
	public static void verifyNumParameterizedRuns() {
		assertEquals("Verifying the number of times the parameterized test method was executed.",
			employeeData().size(), employees.size());
	}

}

根據我自己的業務需求,實現的類似的例子:

package me.zeph.relations.integration;

import com.google.common.collect.Lists;
import me.zeph.relations.config.WebContextConfiguration;
import me.zeph.relations.model.OneParentLocusRecord;
import me.zeph.relations.model.Unit;
import me.zeph.relations.service.Calculator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContextManager;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
@ContextConfiguration(classes = WebContextConfiguration.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
@WebAppConfiguration
public class CalculatorIntegrationTest {

	@Autowired
	private Calculator calculator;

	private Unit c1;

	private Unit c2;
	private Unit af1;
	private Unit af2;
	private double expectedPi;
	private final TestContextManager testContextManager;

	private static final double DELTA = 0.0000001;
	private static final Unit A14 = new Unit(14, 0.0393d);
	private static final Unit A15 = new Unit(15, 0.3541d);
	private static final Unit A16 = new Unit(16, 0.3410d);

	public CalculatorIntegrationTest(Unit c1, Unit c2, Unit af1, Unit af2, double expectedPi) {
		this.c1 = c1;
		this.c2 = c2;
		this.af1 = af1;
		this.af2 = af2;
		this.expectedPi = expectedPi;
		this.testContextManager = new TestContextManager(getClass());
	}

	@Parameters
	public static List<Object[]> data() {
		return Lists.newArrayList(new Object[][]{
				{A14, A15, A14, A15, 7.06733840514568d}
		});
	}

	@Before
	public void injectDependencies() throws Throwable {
		this.testContextManager.prepareTestInstance(this);
	}

	@Test
	public void shouldFindFormulaByPattenAndCalculatePi() {
		OneParentLocusRecord record = new OneParentLocusRecord(c1, c2, af1, af2);
		double pi = calculator.calculatePi(record.getPattern(), record.getP(), record.getQ());
		assertEquals(expectedPi, pi, DELTA);
	}
}

有人可能會說,這個是不是會影響速度,畢竟資料驅動,會跑的資料很多,我自己的測試還好,Spring的上下文在Class級別只加載一次,但是速度快慢還是取決於你的Service層或者Dao是否需要和資料庫打交道。