PowerMock(+Mockito) +TestNG и мокинг статических классов/методов

от автора

На хабре уже была статья с примерами использования PowerMock, но в ней не хватает такого описания, как мокирование статических методов как самостоятельных «единиц» в классе, так и в гибридном использовании, когда часть статических методов у класса мокируются, а часть вызываются реально. Попробую исправить эту нишу.

Для начала создадим демонстрационный класс со статическими методами (коммит):

public class ClassStatic { 	static String getValue() { 		return "value"; 	}  	static String getValue(final String s) { 		return getValue() + s; 	} } 


Добавим простое тестирование статичных методов. Для этого создадим класс ClassStaticTest (коммит):

import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test;  @Test(groups = {"static", "noMock"}) public class ClassStaticTest { 	@DataProvider 	public Object[][] data() throws Exception { 		return new Object[][]{{"", "value"}, {"test", "valuetest"}}; 	}  	@Test 	public void testGetValueVoid() throws Exception { 		Assert.assertEquals(ClassStatic.getValue(), "value"); 	}  	@Test(dataProvider = "data", dependsOnMethods = {"testGetValueVoid"}) 	public void testGetValueAttribute(final String v, final String r) throws Exception { 		Assert.assertEquals(ClassStatic.getValue(v), r); 	} } 

До этого момента мы ни разу не использовали PowerMock, так как он нам не требовался. Теперь же, чтобы сделать мокирование для методов, создадим «костяк»:

import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.IObjectFactory; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test;  @Test(groups = {"static", "mock"}) public class ClassStaticMockTest { 	@ObjectFactory 	public IObjectFactory setObjectFactory() { 		return new PowerMockObjectFactory(); 	} } 

Мы создали класс ClassStaticMockTest, в котором переопределили Object Factory для TestNG (документация)

Добавим тест с мокированием статического метода:

import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.DataProvider; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test;  import static org.mockito.MockitoAnnotations.Mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when;  @Test(groups = {"static", "mock"}) @PrepareForTest({ClassStatic.class}) public class ClassStaticMockTest {  	@Mock 	public ClassStatic classStatic;  	@DataProvider 	public Object[][] data() throws Exception { 		return new Object[][]{{"", "newValue"}, {"test", "newValuetest"}}; 	}  	@ObjectFactory 	public IObjectFactory setObjectFactory() { 		return new PowerMockObjectFactory(); 	}  	@Test(dependsOnGroups = {"noMock"}) 	public void mockGetValueVoid() throws Exception { 		mockStatic(ClassStatic.class); 		when(ClassStatic.getValue()).thenReturn("newValue"); 		Assert.assertEquals(ClassStatic.getValue(), "newValue"); 	} } 

Примечание: не знаю почему (грусть), но без строки @Mock public ClassStatic classStatic; тест не выполняется.

Остался заключительный «аккорд» — гибридный тест, в котором один статическим метод замокирован, а для другого делается реальный вызов (суммарный коммит):

import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.testng.PowerMockObjectFactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.DataProvider; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test;  import static org.mockito.MockitoAnnotations.Mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when;  /** Created by borz on 06.07.13. */ @Test(groups = {"static", "mock"}) @PrepareForTest({ClassStatic.class}) public class ClassStaticMockTest {  	@Mock 	public ClassStatic classStatic;  	@DataProvider 	public Object[][] data() throws Exception { 		return new Object[][]{{"", "newValue"}, {"test", "newValuetest"}}; 	}  	@ObjectFactory 	public IObjectFactory setObjectFactory() { 		return new PowerMockObjectFactory(); 	}  	@Test(dependsOnGroups = {"noMock"}) 	public void mockGetValueVoid() throws Exception { 		mockStatic(ClassStatic.class); 		when(ClassStatic.getValue()).thenReturn("newValue"); 		Assert.assertEquals(ClassStatic.getValue(), "newValue"); 	}  	@Test(dataProvider = "data", dependsOnMethods = {"mockGetValueVoid"}) 	public void testGetValueAttribute(final String v, final String r) throws Exception { 		mockStatic(ClassStatic.class); 		when(ClassStatic.getValue()).thenReturn("newValue"); 		when(ClassStatic.getValue(v)).thenCallRealMethod(); 		Assert.assertEquals(ClassStatic.getValue(v), r); 	} } 

Мы перекрываем вызов метода getValue() и указываем, что при вызове getValue(String value) будет вызван реальный метод у класса, который уже внутри себя вызывает getValue().

PS: Все примеры можно найти на GitHub

ссылка на оригинал статьи http://habrahabr.ru/post/185834/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *