如何在模拟 S/4HANA 响应时检查授权
How to check authorization while mocking S/4HANA responses
我使用 SAP Cloud SDK (js) 从 S/4HANA 获取销售订单和业务合作伙伴。
在测试中,我使用 nock 来模拟 S/4。我只想在目的地正确时匹配响应,即授权正确。
一年前我使用 axios 进行调用,我使用 matchHeader
函数来实现它,就像这样:
nock('https://my123456-api.s4hana.ondemand.com') // ensures the correct url
.persist()
.matchHeader('Authorization', 'Basic dXNlck5hbWU6dXNlclBhc3N3b3Jk') // ensures the correct technical user details
.get(/sap\/opu\/odata\/sap\/API_SALES_ORDER_SRV\/A_SalesOrder(.*)correctSalesOrderId(.*)/) // ensures the correct id
.reply(200, salesOrder);
nock('https://my123456-api.s4hana.ondemand.com')
.persist()
.matchHeader('Authorization', 'Basic d3JvbmdVc2VyTmFtZTp1c2VyUGFzc3dvcmQ=') // ensures the wrong user name
.get(/(.*)/)
.reply(401, "Wrong credentials etc.");
在我开始使用 sdk 之后,我提供的任何目的地(例如,使用错误的用户名)都与第一个和 returns 200 与提供的数据相匹配。我在 github 中做了一些搜索,发现了类似的东西:
function basicCredentials(credentials) {
return `Basic ${Buffer.from(`${credentials.username}:${credentials.password}`, 'ascii').toString('base64')}`;
}
nock('https://my123456-api.s4hana.ondemand.com', {
reqheaders: {
authorization: basicCredentials(givenCorrectBackendDetails())
}
})
.persist()
.get(/sap\/opu\/odata\/sap\/API_SALES_ORDER_SRV\/A_SalesOrder(.*)correctSalesOrderId(.*)/) // ensures the correct id
.reply(200, salesOrder);
nock('https://my123456-api.s4hana.ondemand.com', {
reqheaders: {
authorization: basicCredentials(givenWrongUserName())
}
})
.persist()
.get(/(.*)/) // captures everything
.reply(401, "Wrong credentials etc.");
不幸的是,这给出了相同的结果。我正在使用以下代码发出请求:
function getSalesOrder(Id, backendDetails) {
return SalesOrder.requestBuilder()
.getByKey(Id)
.execute(backendDetails)
.catch(function (error) {
console.error(error);
return null;
});
}
所以我模拟了所有端点和 运行 我所有的测试。在每个测试中只模拟必要的终点是一个解决方案,而且可能会更好。我不想编写测试来检查 sdk 是否完成了它的工作,我们都知道它确实如此:) 尽管如此,我想学习在匹配过程中包含授权的方法。我该怎么办?
根据丹尼斯的回答进行编辑
所以我意识到我应该把问题问得更清楚一点,很抱歉造成了混淆。我使用 getSalesOrder
函数(上面的代码)来获取数据。现在我为同一个端点创建模拟;一次使用 'correct username' ,另一个使用 'wrong username' 并保留它们(上面的第二个代码块,带有 reqheaders 的那个)
我的预期是,在测试中
- 当我提供 'correct username' 时,它应该与第一个匹配,即 return 我应该提供 200 和我提供的模拟数据。
- 当我提供 'wrong username' 时,它应该匹配第二个,即应该 return 401,这将导致 sdk 抛出错误等。
相反,当我提供 'wrong username' 时,nock returns 200 与我提供的数据匹配,即它匹配第一个,而不是我提供的用户名。
这表明,我根本无法检查用户名。显然我做错了,有些事情我不明白。这就是我所追求的:)
更新后的答案:
好的,我明白了。不幸的是,我认为在没有看到实际测试代码的情况下不可能真正回答这个问题。通常,当 nock
ing 没有按预期工作时,我发现要找出问题所在既困难又令人沮丧。对我来说最有效的方法是使各自的 nock
以小的增量或多或少地具体化,并查看何时发生变化(然后我大部分时间都意识到我忘记了一些事情......) .
所以在你的情况下,我会尝试删除 .persist
,然后尝试评论 200-nock
以查看另一个是否匹配,依此类推。
TL;DR: 尝试删除内容,直到发生变化以隔离问题。
原回答:
让我先说明一下我不确定我是否正确理解了您的问题。希望我能分享一些对您有所帮助的见解。
I dont want to write test to check if sdk does its job, we all know it does :)
谢谢你的美言!实际上,我认为大多数人都同意您不必测试依赖项是否有效。话虽如此,我发现最有效的方法是将您对依赖项(在本例中为 SDK)的调用隔离在某处,然后在测试中模拟您的隔离。例如,如果您将对销售订单服务的调用放在一个函数 getSalesOrders
中,那么您可以使用类似 jest.spyOn
的东西来声明您的函数在给定测试中应该 return 的数据,而无需必须处理任何与 HTTP 相关的事情。
或者,如果您不喜欢在运行时覆盖内容,您可以通过依赖注入来实现相同的目的。无论哪种方式,都有一些关于所涉及的代码组织的讨论,所以对此持保留态度。
当谈到在 nock 中包含授权 headers 时,我个人更喜欢你展示的第二种方法(即 reqheaders: { authorization: valueThatIExpectInThisTest }
),因为这最清楚地传达了你的假设是什么以及相应的是什么响应应该是。
最后,我看到您在所有示例中都使用了 .persist()
。这是故意的吗?默认情况下,nock
只匹配一次模拟。来自 Java 和 WireMock 我自己,这种在一开始就欺骗了我,但后来我更喜欢它,因为它可以让你更好地控制并防止意外匹配不应该匹配的东西。最后我仍然在每次测试后调用 nock.cleanAll()
,但那只是 "better safe than sorry".
希望对您有所帮助!如果没有,请不要犹豫,提出更多问题!
我使用 SAP Cloud SDK (js) 从 S/4HANA 获取销售订单和业务合作伙伴。
在测试中,我使用 nock 来模拟 S/4。我只想在目的地正确时匹配响应,即授权正确。
一年前我使用 axios 进行调用,我使用 matchHeader
函数来实现它,就像这样:
nock('https://my123456-api.s4hana.ondemand.com') // ensures the correct url
.persist()
.matchHeader('Authorization', 'Basic dXNlck5hbWU6dXNlclBhc3N3b3Jk') // ensures the correct technical user details
.get(/sap\/opu\/odata\/sap\/API_SALES_ORDER_SRV\/A_SalesOrder(.*)correctSalesOrderId(.*)/) // ensures the correct id
.reply(200, salesOrder);
nock('https://my123456-api.s4hana.ondemand.com')
.persist()
.matchHeader('Authorization', 'Basic d3JvbmdVc2VyTmFtZTp1c2VyUGFzc3dvcmQ=') // ensures the wrong user name
.get(/(.*)/)
.reply(401, "Wrong credentials etc.");
在我开始使用 sdk 之后,我提供的任何目的地(例如,使用错误的用户名)都与第一个和 returns 200 与提供的数据相匹配。我在 github 中做了一些搜索,发现了类似的东西:
function basicCredentials(credentials) {
return `Basic ${Buffer.from(`${credentials.username}:${credentials.password}`, 'ascii').toString('base64')}`;
}
nock('https://my123456-api.s4hana.ondemand.com', {
reqheaders: {
authorization: basicCredentials(givenCorrectBackendDetails())
}
})
.persist()
.get(/sap\/opu\/odata\/sap\/API_SALES_ORDER_SRV\/A_SalesOrder(.*)correctSalesOrderId(.*)/) // ensures the correct id
.reply(200, salesOrder);
nock('https://my123456-api.s4hana.ondemand.com', {
reqheaders: {
authorization: basicCredentials(givenWrongUserName())
}
})
.persist()
.get(/(.*)/) // captures everything
.reply(401, "Wrong credentials etc.");
不幸的是,这给出了相同的结果。我正在使用以下代码发出请求:
function getSalesOrder(Id, backendDetails) {
return SalesOrder.requestBuilder()
.getByKey(Id)
.execute(backendDetails)
.catch(function (error) {
console.error(error);
return null;
});
}
所以我模拟了所有端点和 运行 我所有的测试。在每个测试中只模拟必要的终点是一个解决方案,而且可能会更好。我不想编写测试来检查 sdk 是否完成了它的工作,我们都知道它确实如此:) 尽管如此,我想学习在匹配过程中包含授权的方法。我该怎么办?
根据丹尼斯的回答进行编辑
所以我意识到我应该把问题问得更清楚一点,很抱歉造成了混淆。我使用 getSalesOrder
函数(上面的代码)来获取数据。现在我为同一个端点创建模拟;一次使用 'correct username' ,另一个使用 'wrong username' 并保留它们(上面的第二个代码块,带有 reqheaders 的那个)
我的预期是,在测试中
- 当我提供 'correct username' 时,它应该与第一个匹配,即 return 我应该提供 200 和我提供的模拟数据。
- 当我提供 'wrong username' 时,它应该匹配第二个,即应该 return 401,这将导致 sdk 抛出错误等。
相反,当我提供 'wrong username' 时,nock returns 200 与我提供的数据匹配,即它匹配第一个,而不是我提供的用户名。
这表明,我根本无法检查用户名。显然我做错了,有些事情我不明白。这就是我所追求的:)
更新后的答案:
好的,我明白了。不幸的是,我认为在没有看到实际测试代码的情况下不可能真正回答这个问题。通常,当 nock
ing 没有按预期工作时,我发现要找出问题所在既困难又令人沮丧。对我来说最有效的方法是使各自的 nock
以小的增量或多或少地具体化,并查看何时发生变化(然后我大部分时间都意识到我忘记了一些事情......) .
所以在你的情况下,我会尝试删除 .persist
,然后尝试评论 200-nock
以查看另一个是否匹配,依此类推。
TL;DR: 尝试删除内容,直到发生变化以隔离问题。
原回答:
让我先说明一下我不确定我是否正确理解了您的问题。希望我能分享一些对您有所帮助的见解。
I dont want to write test to check if sdk does its job, we all know it does :)
谢谢你的美言!实际上,我认为大多数人都同意您不必测试依赖项是否有效。话虽如此,我发现最有效的方法是将您对依赖项(在本例中为 SDK)的调用隔离在某处,然后在测试中模拟您的隔离。例如,如果您将对销售订单服务的调用放在一个函数 getSalesOrders
中,那么您可以使用类似 jest.spyOn
的东西来声明您的函数在给定测试中应该 return 的数据,而无需必须处理任何与 HTTP 相关的事情。
或者,如果您不喜欢在运行时覆盖内容,您可以通过依赖注入来实现相同的目的。无论哪种方式,都有一些关于所涉及的代码组织的讨论,所以对此持保留态度。
当谈到在 nock 中包含授权 headers 时,我个人更喜欢你展示的第二种方法(即 reqheaders: { authorization: valueThatIExpectInThisTest }
),因为这最清楚地传达了你的假设是什么以及相应的是什么响应应该是。
最后,我看到您在所有示例中都使用了 .persist()
。这是故意的吗?默认情况下,nock
只匹配一次模拟。来自 Java 和 WireMock 我自己,这种在一开始就欺骗了我,但后来我更喜欢它,因为它可以让你更好地控制并防止意外匹配不应该匹配的东西。最后我仍然在每次测试后调用 nock.cleanAll()
,但那只是 "better safe than sorry".
希望对您有所帮助!如果没有,请不要犹豫,提出更多问题!