Mockito @InjectMocks –模拟依赖注入

时间:2020-02-23 14:40:44  来源:igfitidea点击:

Mockito @InjectMocks批注允许我们将模拟的依赖项注入带注释的类模拟对象中。
当我们要模拟的类中具有外部依赖项时,这很有用。
我们可以使用@Mock或者@Spy批注指定要注入的模拟对象。

Mockito @InjectMocks

Mockito尝试使用三种方法之一以指定的顺序注入模拟的依赖项。

  • 基于构造函数的注入–当为类定义了构造函数时,Mockito尝试使用最大的构造函数注入依赖项。

  • 基于Setter方法-当未定义构造函数时,Mockito尝试使用setter方法注入依赖项。

  • 基于字段的–如果没有构造函数或者基于字段的注入可能,那么Mockito尝试将依赖项注入字段本身。

如果只有一个匹配的模拟对象,则模拟将把它注入到对象中。
如果同一类的模拟对象不止一个,则使用模拟对象名称来注入依赖项。

模拟@InjectMocks示例

让我们创建一些具有依赖项的服务和类,以便我们可以看到Mockito依赖项注入了模拟。

服务等级

package com.theitroad.comjectmocksservices;

public interface Service {

	public boolean send(String msg);
}
package com.theitroad.comjectmocksservices;

public class EmailService implements Service {

	@Override
	public boolean send(String msg) {
		System.out.println("Sending email");
		return true;
	}

}
package com.theitroad.comjectmocksservices;

public class SMSService implements Service {

	@Override
	public boolean send(String msg) {
		System.out.println("Sending SMS");
		return true;
	}
}

具有依赖关系的App Service类

package com.theitroad.comjectmocksservices;

//For Constructor Based @InjectMocks injection
public class AppServices {

	private EmailService emailService;
	private SMSService smsService;

	public AppServices(EmailService emailService, SMSService smsService) {
		this.emailService = emailService;
		this.smsService = smsService;
	}

	public boolean sendSMS(String msg) {
		return smsService.send(msg);
	}

	public boolean sendEmail(String msg) {
		return emailService.send(msg);
	}
}
package com.theitroad.comjectmocksservices;

//For Property Setter Based @InjectMocks injection
public class AppServices1 {

	private EmailService emailService;
	private SMSService smsService;

	public void setEmailService(EmailService emailService) {
		this.emailService = emailService;
	}

	public void setSmsService(SMSService smsService) {
		this.smsService = smsService;
	}

	public boolean sendSMS(String msg) {
		return smsService.send(msg);
	}

	public boolean sendEmail(String msg) {
		return emailService.send(msg);
	}

}
package com.theitroad.comjectmocksservices;

//For Field Based @InjectMocks injection
public class AppServices2 {

	private EmailService emailService;
	private SMSService smsService;

	public boolean sendSMS(String msg) {
		return smsService.send(msg);
	}

	public boolean sendEmail(String msg) {
		return emailService.send(msg);
	}

}

@InjectMocks构造函数注入示例

package com.theitroad.mockito.injectmocks;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import com.theitroad.comjectmocksservices.AppServices;
import com.theitroad.comjectmocksservices.AppServices1;
import com.theitroad.comjectmocksservices.AppServices2;
import com.theitroad.comjectmocksservices.EmailService;
import com.theitroad.comjectmocksservices.SMSService;

class MockitoInjectMocksExamples extends BaseTestCase {

	@Mock EmailService emailService;
	
	@Mock SMSService smsService;
	
	@InjectMocks AppServices appServicesConstructorInjectionMock;
	
	@InjectMocks AppServices1 appServicesSetterInjectionMock;
	
	@InjectMocks AppServices2 appServicesFieldInjectionMock;
	
	@Test
	void test_constructor_injection_mock() {
		when(appServicesConstructorInjectionMock.sendEmail("Email")).thenReturn(true);
		when(appServicesConstructorInjectionMock.sendSMS(anyString())).thenReturn(true);
		
		assertTrue(appServicesConstructorInjectionMock.sendEmail("Email"));
		assertFalse(appServicesConstructorInjectionMock.sendEmail("Unstubbed Email"));
		
		assertTrue(appServicesConstructorInjectionMock.sendSMS("SMS"));
		
	}
}

您是否注意到我的测试类正在扩展BaseTestCase
这是在测试之前初始化Mockito模拟,这是该类的代码。

package com.theitroad.mockito.injectmocks;

import org.junit.jupiter.api.BeforeEach;
import org.mockito.MockitoAnnotations;

class BaseTestCase {

	@BeforeEach
	void init_mocks() {
		MockitoAnnotations.initMocks(this);
	}

}

如果您不调用MockitoAnnotations.initMocks(this);,则将获得NullPointerException

另外,我正在使用JUnit 5运行测试用例。

@InjectMocks设置器方法注入示例

@Test
void test_setter_injection_mock() {
	when(appServicesSetterInjectionMock.sendEmail("New Email")).thenReturn(true);
	when(appServicesSetterInjectionMock.sendSMS(anyString())).thenReturn(true);
	
	assertTrue(appServicesSetterInjectionMock.sendEmail("New Email"));
	assertFalse(appServicesSetterInjectionMock.sendEmail("Unstubbed Email"));
	
	assertTrue(appServicesSetterInjectionMock.sendSMS("SMS"));
	
}

@InjectMocks基于字段的注入示例

@Test
void test_field_injection_mock() {
	when(appServicesFieldInjectionMock.sendEmail(anyString())).thenReturn(true);
	when(appServicesFieldInjectionMock.sendSMS(anyString())).thenReturn(true);
	
	assertTrue(appServicesFieldInjectionMock.sendEmail("Email"));
	assertTrue(appServicesFieldInjectionMock.sendEmail("New Email"));
	
	assertTrue(appServicesFieldInjectionMock.sendSMS("SMS"));
	
}