gpt4 book ai didi

unit-testing - 使用 spock mocking 或 grails mockFor : Null pointer exception 进行单元测试

转载 作者:行者123 更新时间:2023-12-02 03:28:19 27 4
gpt4 key购买 nike

我正在对老板编写的一些代码进行单元测试。他正在画空白,而我是 TDD 的新手,所以请和我一起集思广益。

我要测试的文件,EmailAssist 是此处未显示的服务的辅助类。 EmailAssist 应该引用其他几个服务,包括 sectionService,如图所示。

   class EmailAssist {
def sectionService
//condensed to relevant items
List<CommonsMultipartFile> attachments
Map emailMap =[:]
User user
Boolean valid

public EmailAssist(){
valid = false
}

public EmailAssist(GrailsParameterMap params, User user){
//irrelevant code here involving snipped items
this.setSections(params.list('sections'))
//series of other similar calls which are also delivering an NPE
}
//third constructor using third parameter, called in example but functionally
//similar to above constructor.

//definition of errant function
void setSections(List sections) {
emailMap.sections = sectionService.getEmailsInSectionList(sections, user)
}

被调用的SectionService部分如下。

       Set<String> getEmailsInSectionList(List<String> sections, User user) {
if(sections && user){
//code to call DB and update list
}
else{
[]
}

我的测试没有提供一个部分,所以这应该返回一个空列表,特别是因为我什至无法在单元测试中访问数据库。

单元测试如下。这是使用 mockFor,因为 spock 的模拟功能似乎并不是我所需要的。

@TestMixin(GrailsUnitTestMixin)
class EmailAssistSpec extends Specification {
@Shared
GrailsParameterMap params
@Shared
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
@Shared
User user
@Shared
def sectionService

def setup() {
user = new User(id: 1, firstName: "1", lastName: "1", username: "1", email: "1@1.com")
def sectionServiceMock = mockFor(SectionService)
sectionServiceMock.demand.getEmailsInSectionList() {
[]
}
sectionService = sectionServiceMock.createMock()
}

def cleanup(){
}
void testGetFiles(){
when:
//bunch of code to populate request

params = newGrailsParameterMap([:], request)
EmailAssist assist = new EmailAssist(params, request, user)
//Above constructor call generates NPE

具体的NPE如下:java.lang.NullPointerException:无法在空对象上调用方法 getEmailsInSectionList()在

        emailMap.sections = sectionService.getEmailsInSectionList(sections, user)

这是我的 setSections 函数的主体,供那些在家玩的人使用。 NPE 堆栈源 self 的测试文件中的构造函数调用。我也尝试过使用 spock 风格的模拟,但该服务仍被视为 null。最糟糕的是,构造函数甚至不是该测试应该测试的内容,它只是拒绝传递它,结果导致测试无法运行。

如果我可以提供更多详细信息来澄清问题,请告诉我,谢谢!

编辑:我将构造函数中的 setter 短路以完成测试,但这在测试覆盖率中留下了一些我无法弄清楚如何修复的明显漏洞。也许我的 mock 位于错误的地方? Spock 的模拟文档对于复杂函数不是很方便。

最佳答案

您收到 NPE 是因为未创建 EmailAssist 中的 sectionServiceEmailAssist 的构造函数调用 sectionService.getEmailsInSectionList(sections, user) 并且因为 sectionService 为 null,所以您得到一个 NPE。

虽然您在测试 setup() 中创建了一个名为 sectionService 的模拟,但它不会自动连接/注入(inject)到 EmailAssist类(class)。您在 Grails 单元测试中获得的自动连接非常有限——文档并不清楚实际创建了什么 bean(而且我对 Grails/Groovy 还比较陌生)。

您需要在创建emailAssist 时注入(inject)sectionService,否则为时已​​晚,无法逃脱NPE。

如果您将单元测试中对构造函数的调用修改为:

@TestMixin(GrailsUnitTestMixin)
class EmailAssistSpec extends Specification {
@Shared
GrailsParameterMap params
@Shared
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
@Shared
User user
@Shared
def mockSectionService = Mock(SectionService)

def setup() {
user = new User(id: 1, firstName: "1", lastName: "1", username: "1", email: "1@1.com")
}

def cleanup(){
}

void testGetFiles(){
given: "an EmailAssist class with an overridden constructor"

EmailAssist.metaClass.constructor = { ParamsType params, RequestType request, UserType user ->
def instance = new EmailAssist(sectionService: mockSectionService)
instance // this returns instance as it's the last line in the closure, but you can put "return instance" if you wish
}

// note that I've moved the population of the request to the given section
//bunch of code to populate request
params = newGrailsParameterMap([:], request)

// this is the list of parameters that you expect sectionService will be called with
def expectedSectionList = ['some', 'list']

when: "we call the constructor"
EmailAssist assist = new EmailAssist(params, request, user)

then: "sectionService is called by the constructor with the expected parameters"
1 * mockSectionService.getEmailsInSectionList(expectedSectionList, user)
// replace a parameter with _ if you don't care about testing the parameter

此答案基于 Burt Beckwith 的博文 here .

关于unit-testing - 使用 spock mocking 或 grails mockFor : Null pointer exception 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28993677/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com