我正在使用node.js和typescript来构建一个webapi。对于数据库,我使用mariadb(mysql)。我已经使用repository模式+工作单元构建了这个项目(我不是.net开发人员,但我在一家使用.net的公司工作)。我正在尝试编写测试,到目前为止,我已经能够使用chai和typemoq库为域模型和服务编写测试。我想对于存储库来说也是可行的。我面临的问题(目前)是在我使用服务的路线上。是否可以测试路由并模拟服务?我见过许多节点教程,其中他们为路由编写了测试,但他们只是检查响应,没有模仿任何东西。这不是类似于集成测试而不是单元测试吗?如何将tdd应用于节点?
举个例子:
router.post('/register', (req, res, next) => {
try {
let newUser = <RegisterUserDTO>req.body;
let uow = <IUnitOfWork>req.uow;
let userRepository = new UserRepository(uow);
let userService: IUserService = new UserService(userRepository);
userService.getByUsername(newUser.username)
.then((user:User) => {
if(!user) {
userService.getByEmail(newUser.email).then(user => {
if(!user) {
userService.insertUser(newUser)
.then((result) => {
res.json({
success: true,
msg: "User registered",
userId: result.insertId
});
})
.catch(err => {
res.json({ errorMessage: err.message, errorStackTrace: err.stack });
});
}else {
res.json({ success: false, msg: "This email already exists" });
}
});
}else {
res.json({ success: false, msg: "This username already exists" });
}
})
}
catch(err) {
res.json({ errorMessage: err.message, errorStackTrace: err.stack });
}
});
如何模拟userservice并测试此路由?这是使用node的“错误”方法吗?
提前谢谢
1条答案
按热度按时间guz6ccqo1#
为了更容易测试,我会将更多的逻辑引入到您的服务中,并划分路由和服务的责任。在路由中有很多if语句,甚至创建了一个存储库,这将使测试变得非常困难,并赋予路由比路由请求和响应更大的责任。
这里有一个方法来构造它。
用户.route.js
用户路由的责任
如果分析上面的代码,路由的责任不再是确定适当的响应消息,检查用户是否存在,等等。它的工作是从userservice获取响应并将其发送给用户。这简化了我需要测试的内容。因为在路由测试中,我只关心路由中立即发生的事情,所以我可以完全删除userservice.register。userservice返回的是promise resolve还是promise rejection并不重要,只是路由正确地处理了这些场景。
上面的代码和url“/user/register”可以很容易地用sinon.js进行测试。节点只加载一次“required”模块,因此在用户路由的单元测试中,您可以加载userservice,向register函数添加存根,然后当userroute加载userservice时,它将获得存根函数。
下面是一个使用存根方法的用户路由测试示例
user.routes.test.js文件
上面的测试是一个trip wire,确保用户路由充当url“/user/register”上的事件处理程序。它不是对userservice内部逻辑的测试。在这个设计中,userroute和userservice有两个独立的职责。
用户服务的责任
register返回解析为响应对象或用错误对象拒绝的承诺。另一个实用程序类负责将结果转换为状态代码500(如果承诺被拒绝),或者转换为json(如果承诺被解析)。测试下面的代码可以使用前面的stubing方法来模拟数据库客户机/模块,使其看起来像用户已经存在,然后确认返回了相应的消息。
用户.serivice.js
通过将操作结果 Package 为承诺,可以分离用户服务了解请求和响应的需求。对我来说,一个error对象会导致所有操作都中止,所以reject(err)通常就足够了,但是您可以使用
reject({message:"ssfsfs",code:500,error:err})
或创建一个ApplicationError
您用于所有拒绝的类型。这是一种让错误从业务逻辑冒泡到http层的好方法,而不必将请求和响应对象深入到业务逻辑中。