我正在开发一个春季启动应用程序。该服务方法使用GridFsTemplate将PDF上传到mongodb的repo中,该服务在服务中自动连接。该文件上传服务方法通过邮差rest客户端按预期工作。但是,当我尝试运行单元测试时;调用相同的服务方法,SpringData GridFsTemplate没有初始化(在MongoDB中,您可以使用GridFS来存储二进制文件)。这将导致org.springframework.data.mongodb.gridfs.GridFsTemplate.store(…)抛出NullPointerException。拜托,你能帮帮我吗,我已经被困在这里一天了。
下面是我的服务实现:
@Service
public final class UploadServiceImpl implements UploadService {
@Autowired
private SequenceRepository sequenceDao;
@Autowired (required = true)
private GridFsTemplate gridFsTemplate;
@Override
public Long uploadFile(Invoice uploadedInvoice) {
ByteArrayInputStream byteArrayInputStream = null;
if (checkContentType(invoiceInfo.getContentType())) {
invoiceInfo.setPaymentID(sequenceDao.getNextSequenceId(INVOICE_UPLOAD_SEQ_KEY));
byteArrayInputStream = new ByteArrayInputStream(uploadedInvoice.getFileContent());
//Error thrown is java.lang.NullPointerException: null, where gridFsTemplate is null and basically autowire does not work when test is run.
GridFSFile gridFSUploadedFile= gridFsTemplate.store(byteArrayInputStream, invoiceInfo.getFileName(), invoiceInfo.getContentType(), invoiceInfo);
return 1l;
} else {
return 2l;
}
}
下面是服务的Unit Test类@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration
public class UploadServiceTest {
@Mock
private SequenceRepository sequenceRepositoryMock;
@Autowired
private GridFsTemplate gridFsTemplateMock;
@Mock
private Invoice invoiceMock;
@InjectMocks
private static UploadService uploadService = new UploadServiceImpl();
DBObject fileMetaData = null;
DB db = null;
Jongo jongo = null;
@Before
public void setUp() throws Exception {
db = new Fongo("Test").getDB("Database");
jongo = new Jongo(db);
}
@Test
public void testUploadFile() {
//test 1
Long mockPaymentNo = new Long(1);
Mockito.when(sequenceRepositoryMock.getNextSequenceId(INVOICE_SEQUENCE)).thenReturn(mockPaymentNo);
assertEquals(mockPaymentNo, (Long) sequenceRepositoryMock.getNextSequenceId(INVOICE_SEQUENCE));
//test 2
Invoice dummyInvoice = getDummyInvoice();
InvoiceInfo dummyInvoiceInfo = dummyInvoice.getInvoiceInfo();
MongoCollection invoicesCollection = jongo.getCollection("invoices");
assertNotNull(invoicesCollection.save(dummyInvoiceInfo));
assertEquals(1, invoicesCollection.save(dummyInvoiceInfo).getN());
System.out.println("TEST 2 >>>>>>>>>>>>>>>>>> "+ uploadService);
//test 3 : The following line is the cause of the exception, the service method is called but the GridFsTemplate is not initialized when the test is run. But it works when the endpoint is invoked via postman
uploadService.uploadFile(dummyInvoice);
System.out.println("TEST 3 >>>>>>>>>>>>>>>>>> ");
}
}
问题是因为你使用@ injectmock来自动连接你的UploadService。UploadService自动连接另外两个bean SequenceRepository和GridFsTemplate。
如果你在做TDD或者没有(我们可以先改变测试)-这个代码的客户端不知道额外的依赖,因为它是完全隐藏的
Javadoc声明:
Mockito将只尝试通过构造函数注入来注入mock,Setter注入,或属性注入,按顺序和描述在下面。如果以下任何一种策略失败,那么Mockito就不会失败报告失败;也就是说,你必须自己提供依赖项。
解决方案是使用UploadServiceImpl构造函数来自动连接bean:
@Service
public final class UploadServiceImpl implements UploadService {
private final SequenceRepository sequenceDao;
private final GridFsTemplate gridFsTemplate;
private final PlannerClient plannerClient;
@Autowired
public PlannerServiceImpl(PlannerClient plannerClient, GridFsTemplate gridFsTemplate, SequenceRepository sequenceDao) {
this.plannerClient = plannerClient;
}
...
}
当需要更多的依赖项时,它们会清晰地出现,因为它们是在构造函数
中初始化的。更详细:https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/