我对 Mockito 和 jUnit 非常陌生,我尝试学习正确的方法来执行 TDD。我需要几个示例,以便我可以使用 mockito 编写单元测试
以下是我的 Controller 类,它上传文件并对此文件输入执行一些操作。
@Controller
@RequestMapping("/registration")
public class RegistrationController {
@Autowired
private RegistrationService RegistrationService;
@Value("#{Properties['uploadfile.location']}")
private String uploadFileLocation;
public RegistrationController() {
}
@RequestMapping(method = RequestMethod.GET)
public String getUploadForm(Model model) {
model.addAttribute(new Registration());
return "is/Registration";
}
@RequestMapping(method = RequestMethod.POST)
public String create(Registration registration, BindingResult result,ModelMap model)
throws NumberFormatException, Exception {
File uploadedFile = uploadFile(registration);
List<Registration> userDetails = new ArrayList<Registration>();
processUploadedFile(uploadedFile,userDetails);
model.addAttribute("userDetails", userDetails);
return "registration";
}
private File uploadFile(Registration registration) {
Date dt = new Date();
SimpleDateFormat format = new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss");
File uploadedFile = new File(uploadFileLocation
+ registration.getFileData().getOriginalFilename() + "."
+ format.format(dt));
registration.getFileData().transferTo(uploadedFile);
return uploadedFile;
}
private void processUploadedFile(File uploadedFile, List<Registration> userDetails)
throws NumberFormatException, Exception {
registrationService.processFile(uploadedFile, userDetails);
}
}
任何机构都可以提出一些示例,我如何使用 mockito 编写测试用例?
编辑 我已经写下了以下测试类(class),但如何进一步进行
@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml"})
public class BulkRegistrationControllerTest {
@InjectMocks
private RegistrationService registrationService= new RegistrationServiceImpl();
@Mock
private final ModelMap model=new ModelMap();
@InjectMocks
private ApplicationContext applicationContext;
private static MockHttpServletRequest request;
private static MockHttpServletResponse response;
private static RegistrationController registrationController;
@BeforeClass
public static void init() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
registrationController = new RegistrationController();
}
public void testCreate()
{
final String target = "bulkRegistration";
BulkRegistration bulkRegistration=new BulkRegistration();
final BindingResult result=new BindingResult();
String nextPage=null;
nextPage = bulkRegistrationController.create(bulkRegistration, result, model);
assertEquals("Controller is not requesting the correct form",nextPage,
target);
}
}
最佳答案
您似乎在测试中交叉了几件事。有集成测试和单元测试。集成测试将测试所有连接的所有内容(或几乎所有内容) - 因此您使用的 Spring 配置文件非常接近真实的配置文件,并且对象的真实示例被注入(inject)到您的测试类中。这主要是我使用 @ContextConfiguration
但我将它与 @RunWith(SpringJUnit4ClassRunner.class)
如果您使用 Mockito(或任何模拟框架),通常是因为您希望将您正在测试的类与其他类的实际实现隔离开来。因此,例如,不必设计一种方法让您的 RegistrationService 抛出 NumberFormatException 来测试该代码路径,您只需告诉模拟 RegistrationService 去做。还有许多其他示例表明使用模拟比使用真实的类实例更方便。
所以,小课结束了。以下是我将如何重写您的测试类(带有一个额外的示例并在此过程中进行了评论)。
@RunWith(MockitoJUnitRunner.class)
public class RegistrationControllerTest {
// Create an instance of what you are going to test.
// When using the @InjectMocks annotation, you must create the instance in
// the constructor or in the field declaration.
@InjectMocks
private RegistrationController controllerUT = new RegistrationController();
// The @Mock annotation creates the mock instance of the class and
// automatically injects into the object annotated with @InjectMocks (if
// possible).
@Mock
private RegistrationService registrationService;
// This @Mock annotation simply creates a mock instance. There is nowhere to
// inject it. Depending on the particular circumstance, it may be better or
// clearer to instantiate the mock explicitly in the test itself, but we're
// doing it here for illustration. Also, I don't know what your real class
// is like, but it may be more appropriate to just instantiate a real one
// than a mock one.
@Mock
private ModelMap model;
// Same as above
@Mock
private BulkRegistration bulkRegistration;
// Same as above
@Mock
private FileData fileData;
@Before
public void setUp() {
// We want to make sure that when we call getFileData(), it returns
// something non-null, so we return the mock of fileData.
when(bulkRegistration.getFileData()).thenReturn(fileData);
}
/**
* This test very narrowly tests the correct next page. That is why there is
* so little expectation setting on the mocks. If you want to test other
* things, such as behavior when you get an exception or having the expected
* filename, you would write other tests.
*/
@Test
public void testCreate() throws Exception {
final String target = "bulkRegistration";
// Here we create a default instance of BindingResult. You don't need to
// mock everything.
BindingResult result = new BindingResult();
String nextPage = null;
// Perform the action
nextPage = controllerUT.create(bulkRegistration, result, model);
// Assert the result. This test fails, but it's for the right reason -
// you expect "bulkRegistration", but you get "registration".
assertEquals("Controller is not requesting the correct form", nextPage,
target);
}
/**
* Here is a simple example to simulate an exception being thrown by one of
* the collaborators.
*
* @throws Exception
*/
@Test(expected = NumberFormatException.class)
public void testCreateWithNumberFormatException() throws Exception {
doThrow(new NumberFormatException()).when(registrationService)
.processFile(any(File.class), anyList());
BindingResult result = new BindingResult();
// Perform the action
controllerUT.create(bulkRegistration, result, model);
}
}
关于java - 如何使用 mockito 为 Controller 类编写单元测试用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8894637/