我是新的反应,也是功能,命令,声明的条款。而且我知道纯函数很容易测试。我自学成才用Javascript编程。到目前为止,它正在工作,但我的目标是学习编写干净和可维护的代码。
我的问题是下面的addProductToSaleList
方法是坏的和不可测试的,因为它是必要的?我怎么能以不同的方式做到这一点。
class SaleComponent extends React.Component {
addProductToSaleList = (values, dispatch, props) => {
//filter product from productList
const productFound = props.productList.filter(product => {
if (values.productCode === product.code.toString()) {
return product
}
return undefined
})[0]
if (productFound) {
// filter sale list to check if there is already product in the list.
const detailFound = props.saleItem.details.filter(detail => {
if (productFound.name === detail.product) {
return detail
}
return undefined
})[0]
// if it is exist just increment the qty
if (detailFound) {
const { sub_total, ...rest } = detailFound
props.dispatcher('UPDATE_SALEDETAIL_ASYNC', {
...rest,
qty: parseInt(detailFound.qty, 10) + 1
})
// if it is not exist add new one
} else {
props.dispatcher('ADD_SALEDETAIL_ASYNC', {
product: productFound.id,
price: productFound.price,
qty: 1
})
}
} else {
alert('The product code you add is not exist in product list');
}
}
render() {
// Render saleList
}
}
答案 0 :(得分:2)
我相信这个问题应该转到Code Review,但我会试一试。部分代码可以改进
const productFound = props.productList.filter(product => {
if (values.productCode === product.code.toString()) {
return product
}
return undefined
})[0]
首先,filter函数接收回调,并且每个项目都将执行回调。如果回调返回一个解释为true的值,它将返回函数将构建的新数组中的项。否则,它将跳过该项目。假设您正在尝试在代码中找到一个项目,您可以使用函数find直接返回该元素(不需要[0]
),或者如果该项不是找到。所以你的代码可以重写为
const productFound = props.productList.find(product => values.productCode === product.code.toString());
注意:没有IE支持。
然后,如果找不到该值,您只需提醒并执行early return。 (您可能还希望以不同的方式处理错误,格式比普通警报更好。)
代码看起来像
if (!productFound) {
alert('The product code you add is not exist in product list');
return;
}
// rest of the function
为了查找详细信息,您还可以使用find
方法
const detailFound = props.saleItem.details.find(detail => productFound.name === detail.product);
然后只需调用代码的其余部分
// if it is exist just increment the qty
if (detailFound) {
const { sub_total, ...rest } = detailFound
props.dispatcher('UPDATE_SALEDETAIL_ASYNC', {
...rest,
qty: parseInt(detailFound.qty, 10) + 1
})
// if it is not exist add new one
} else {
props.dispatcher('ADD_SALEDETAIL_ASYNC', {
product: productFound.id,
price: productFound.price,
qty: 1
})
}
另一项改进:
您正在接收调度功能作为参数,但您并未使用它。所以你可以从函数声明中删除它
(values, props) => { ... }
你可以把最后一部分分成两个不同的功能,比如
const getAction = details => `${detailFound ? 'UPDATE' : 'ADD'}_SALEDETAIL_ASYNC`;
const getObject = (details, productFound) => {
if (!details) {
return {
product: productFound.id,
price: productFound.price,
qty: 1
};
}
const { sub_total, ...rest } = detailFound;
return {
...rest,
qty: parseInt(detailFound.qty, 10) + 1
};
}
然后只需致电
props.dispatcher(getAction(details), getObject(details, productFound));
最终结果看起来像
addProductToSaleList = (values, props) => {
//filter product from productList
const productFound = props.productList.find(product => values.productCode === product.code.toString());
if (!productFound) {
alert('The product code you add is not exist in product list');
return;
}
// filter sale list to check if there is already product in the list.
const detailFound = props.saleItem.details.find(detail => productFound.name === detail.product);
const getAction = details => `${details ? 'UPDATE' : 'ADD'}_SALEDETAIL_ASYNC`;
const getObject = (details, productFound) => {
if (!details) {
return {
product: productFound.id,
price: productFound.price,
qty: 1
};
}
const { sub_total, ...rest } = details;
return {
...rest,
qty: parseInt(details.qty, 10) + 1
};
}
props.dispatcher(getAction(details), getObject(details, productFound));
}
我的问题是下面的方法addProductToSaleList是坏的 不可测试,因为这是必要的
你的代码是可测试的,没有外部依赖。所以你可以传递模拟的值和道具,并添加单元测试。这意味着,传递假的values
和props
(它们只是普通的js对象)并对其进行断言。
例如:
您可以模拟dispatcher
函数并在productList和saleItem.details
中给出假值,您可以看到是否使用正确的值调用dispatcher
。你应该测试那个
Mock alert
函数(同样,我会使用另一种UI方法)并验证它是否被调用,并且没有其他代码被调用(断言你的假dispatcher
未被调用)。像这样:
let actionToAssert;
let objectToAssert;
let values = { productCode: 'somecode' };
let props = {
productList: // your item listm with id and price, name, etc,
saleItem: {
details: // your details array here
}
dispatcher: (action, newObject) => {
actionToAssert = action;
objectToAssert = newObject;
}
}
addProductToSaleList(values, props); // make here assertions over actionToAssert and objectToAssert