Moq - Invocation count does not match - unit-testing

I appear to be having an issue when I go to verify the number of times a method has been called with certain arguments. I've pasted the relevant code and unit test below. My unit test is failing saying that the first Update of InventoryTransferItemTransaction is not being called at all; while the second is being called twice. I've tried simplifying out the arguments section to only look at the transferType; but still get the error. Debugging the code shows that the correct values are being passed through. It feels like I'm missing something, but can't quite put my finger on it.
Error messages:
Expected invocation on the mock once, but was 0 times: t => t.Update(It.Is<InventoryTransferItemTransaction>(args => (((((!(args.Created.IsNull()) && args.CreatedBy == User.GetNameFromContext()) && args.InventoryTransferItemId == 12) && !(args.Modified.IsNull())) && args.ModifiedBy == User.GetNameFromContext()) && args.Quantity == -10) && (Int32)args.TransactionType == 2))
Expected invocation on the mock once, but was 2 times: t => t.Update(It.Is<InventoryTransferItemTransaction>(args => (((((!(args.Created.IsNull()) && args.CreatedBy == User.GetNameFromContext()) && args.InventoryTransferItemId == 12) && !(args.Modified.IsNull())) && args.ModifiedBy == User.GetNameFromContext()) && args.Quantity == 0) && (Int32)args.TransactionType == 5))
Unit Test:
[Test]
public void CanRemoveTransferItem()
{
const int TRANSFER_ITEM_ID = 12;
const int QTY = 10;
var inventoryTransferFactoryMock = new Mock<IInventoryTransferFactory>();
inventoryTransferFactoryMock.Setup(t => t.GetTransferItem(TRANSFER_ITEM_ID))
.Returns(new InventoryTransferItem
{
InventoryTransferItemId = TRANSFER_ITEM_ID,
Quantity = QTY
});
inventoryTransferFactoryMock.Setup(t => t.CreateInventoryTransferItemTransaction())
.Returns(new InventoryTransferItemTransaction());
var inventoryTransferManager = new InventoryTransferManager(inventoryTransferFactoryMock.Object, null, null,
null, null);
inventoryTransferManager.RemoveTransferItem(TRANSFER_ITEM_ID);
inventoryTransferFactoryMock.Verify(t=>t.GetTransferItem(TRANSFER_ITEM_ID), Times.Once);
inventoryTransferFactoryMock.Verify(
t =>
t.Update(
It.Is<InventoryTransferItem>(
args =>
args.Quantity == 0 && args.ModifiedBy == User.GetNameFromContext() &&
!args.Modified.IsNull() && !args.ClosedDate.IsNull())), Times.Once);
inventoryTransferFactoryMock.Verify(t => t.CreateInventoryTransferItemTransaction(), Times.Exactly(2));
inventoryTransferFactoryMock.Verify(
t =>
t.Update(It.Is<InventoryTransferItemTransaction>(
args =>
!args.Created.IsNull() && args.CreatedBy == User.GetNameFromContext() &&
args.InventoryTransferItemId == TRANSFER_ITEM_ID &&
!args.Modified.IsNull() && args.ModifiedBy == User.GetNameFromContext() &&
args.Quantity == -QTY &&
args.TransactionType == InventoryTransferTransactionType.TransferAdjusted)), Times.Once);
inventoryTransferFactoryMock.Verify(
t =>
t.Update(It.Is<InventoryTransferItemTransaction>(
args =>
!args.Created.IsNull() && args.CreatedBy == User.GetNameFromContext() &&
args.InventoryTransferItemId == TRANSFER_ITEM_ID &&
!args.Modified.IsNull() && args.ModifiedBy == User.GetNameFromContext() &&
args.Quantity == 0 &&
args.TransactionType == InventoryTransferTransactionType.ClosedManually)), Times.Once);
}
RemoveTransferItem:
public void RemoveTransferItem(int inventoryTransferItemId)
{
using (var trx = new TransactionWrapper())
{
var transferItem = inventoryTransferFactory.GetTransferItem(inventoryTransferItemId);
transferItem.Modified = DateTime.Now;
transferItem.ModifiedBy = User.GetNameFromContext();
var originalQuantity = transferItem.Quantity;
transferItem.Quantity = 0;
transferItem.ClosedDate = DateTime.Now;
inventoryTransferFactory.Update(transferItem);
LogTransferItemTransaction(transferItem.InventoryTransferItemId, InventoryTransferTransactionType.TransferAdjusted, -originalQuantity);
LogTransferItemTransaction(transferItem.InventoryTransferItemId, InventoryTransferTransactionType.ClosedManually, 0);
trx.Complete();
}
}
LogTransferItemTransaction:
internal void LogTransferItemTransaction(int transferItemId, InventoryTransferTransactionType transferType, int quantity, int? employeeId = null)
{
var newTransaction = inventoryTransferFactory.CreateInventoryTransferItemTransaction();
newTransaction.Created = DateTime.Now;
newTransaction.CreatedBy = User.GetNameFromContext();
newTransaction.EmployeeId = employeeId;
newTransaction.InventoryTransferItemId = transferItemId;
newTransaction.Modified = DateTime.Now;
newTransaction.ModifiedBy = User.GetNameFromContext();
newTransaction.Quantity = quantity;
newTransaction.TransactionType = transferType;
inventoryTransferFactory.Update(newTransaction);
}

Figured it out. This line was the problem:
inventoryTransferFactoryMock.Setup(t => t.CreateInventoryTransferItemTransaction())
.Returns(new InventoryTransferItemTransaction());
It was returning the same object through the multiple iterations. Hence why the 2nd invocation appeared to be called twice while the first 0 times.
Changing it to this fixed the test:
inventoryTransferFactoryMock.Setup(t => t.CreateInventoryTransferItemTransaction())
.Returns(() => new InventoryTransferItemTransaction());

Related

Problem with state change using useState in if else statement

I got some issue with useState and "if else" statement. I wanted to change displayed text with a click.
When I checking if counter icrement is working, it works, but when I add setText in "if else" statement there is a problem and just doesnt work properly. Icnrement strats to work strange when clicking and change a text is just imposible. Even in console increment looks wrong. Can someone help what I am doing wrong?
let counter = 0;
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") || e.target.classList.contains("fa-angle-left")
) {e.target.classList.contains("fa-angle-right") ? counter++ : counter--;
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Txt3")
} else if (counter > 2) {
counter = 0;
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
counter = 2;
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Txt1");
}
}
};
Every time setTxt('...') is executed, the component is re-rendered and the function executes again, so counter gets the value of 0.
If you want to preserve the value of your counter between renders, put it as a new state ( const [counter, setCounter] = useState(0) )
OK, #AdriánFernándezMartínez I did that way and its close. Just after first clik, in a first "if" (if (counter === 1)) console shows 0 and i have to click twice to chage it and change Txt (but is should be 1 after setCounter(counter + 1)). Next, in a third "if" (else if (counter > 2)) console shows 3 and again I need to click twice to change Txt (after 1st click its 0 and after 2nd it become 1). Still need help.
const [counter, setCounter] = useState(0);
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") ||
e.target.classList.contains("fa-angle-left")
) {
e.target.classList.contains("fa-angle-right")
? setCounter(counter + 1)
: setCounter(counter + 1);
console.log(counter);
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Text3");
} else if (counter > 2) {
setCounter(0);
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
setCounter(2);
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Text1");
}
}
};

Hello everyone, please help me check this IF statement in Google app script

I want to make a code to assign logic input for my sheet. I use IF to make it. My code ran successfully but the logic didn't work. I have checked it many times, but I couldn't find something wrong. Can you help me with this? I'm stuck. Please review my example sheet and my script for more information. Thank you! https://docs.google.com/spreadsheets/d/1eV2SZ45Gs6jISgh_p6RIx-rfOGlHUM6vF114Mgf6c58/edit#gid=0
function logic(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var activeCell = ss.getActiveCell();
if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "Yes") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue("1");
} if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "Hafl") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue("1/2");
} if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "No") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue(0);
}
}
You can simplify your code this way.
(Note that I use the const variable declaration instead of var (ES6 - V8 engine))
function logic() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const activeCell = ss.getActiveCell();
const activeCellValue = activeCell.getValue();
if (activeCell.getColumn() === 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama") {
switch(activeCellValue) {
case 'Yes':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('1');
break;
case 'Half':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('1/2');
break;
case 'No':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('0');
break;
}
}
}
This way you only have to test the common conditions once.
Using the Switch function clearly shows the behavior of the script depending on the input value 'ActiveCellValue'.
If you need that only one action resolve per run, you need to use else if to chain the statements:
if(statement){
Action
}else if (statement2){
Action2
}else if...

How to update a variable maintaining the length of a list in a cascade-like structure?

class CoinData {
var _controller = StreamController<Map<String,dynamic>>();
.....
Stream<Map<String,dynamic>> getAllCurrentRates() {
int numAssets = 0;
int counter = 0;
this.listAllAssets()
.then((list) {
if (list != null) {
numAssets = list.length;
List<Map<String, dynamic>>.from(list)
.where((map) => map["type_is_crypto"] == 1)
.take(3)
.map((e) => e["asset_id"].toString())
.forEach((bitCoin) {
this.getCurrentRate(bitCoin)
.then((rate) => _controller.sink.add(Map<String,dynamic>.from(rate)))
.whenComplete(() {
if (++counter >= numAssets) _controller.close();
});
});
}
});
return _controller.stream;
}
.....
}
The length of returned list is around 2500 and this value is assumed by numAssets, however as you see that list is modified later and therefore its length is less, then the evaluation (++counter >= numAssets) is incorrect. So, is it possible to fix that code maintaining its current structure?
.take(3) is temporal, it shall be removed later.

Have any way to modify the SLA DateTime by the day of Assigning Date?

As the question I'm asking above on CaseScrren (screenID:CR306000), the default value it sets SLA Datetime by the datetime of creating case.
For example: Case 1 created on 01/01/2016 09:58 AM, severity: H for 3Days so SLA Datetime should be on 01/03/2016 09:58 AM. But case 1 I assigned to owner on 01/02/2016 09:58 AM. I just added new field name: Test SLA
[PXDBDate(PreserveTime = true, DisplayMask = "g")]
[PXUIField(DisplayName="Test SLA")]
[PXFormula(typeof(Default<CRCase.contractID, CRCase.severity, CRCase.caseClassID>))]
protected void CRCase_UsrTestSLA_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e)
{
CR.CRCase row = e.Row as CR.CRCase;
if (row == null || row.AssignDate == null) return;
if (row.ClassID != null && row.Severity != null)
{
CR.CRClassSeverityTime severity = PXSelect<CR.CRClassSeverityTime,
Where<CR.CRClassSeverityTime.caseClassID, Equal<Required<CR.CRClassSeverityTime.caseClassID>>,
And<CR.CRClassSeverityTime.severity, Equal<Required<CR.CRClassSeverityTime.severity>>>>>
.Select(Base,row.ClassID,row.Severity);
if (severity != null && severity.TimeReaction != null)
{
e.NewValue = ((DateTime)row.AssignDate).AddMinutes((int)severity.TimeReaction);
e.Cancel = true;
}
}
if (row.Severity != null && row.ContractID != null)
{
Contract template = PXSelect<Contract, Where<Contract.contractID, Equal<Required<CRCase.contractID>>>>
.Select(Base, row.ContractID);
if (template == null) return;
ContractSLAMapping sla = PXSelect<ContractSLAMapping,
Where<ContractSLAMapping.severity, Equal<Required<CRCase.severity>>,
And<ContractSLAMapping.contractID, Equal<Required<CRCase.contractID>>>>>
.Select(Base, row.Severity, template.TemplateID);
if (sla != null && sla.Period != null)
{
e.NewValue = ((DateTime)row.AssignDate).AddMinutes((int)sla.Period);
e.Cancel = true;
}
}
}

Refactoring messy if else statement

I am working on a legacy code base which has the following snippet:
if ((results[0].Length == 0))
customerName = "";
else
customerName = results[0].Substring(18);
if ((results[1].Length == 0))
meterSerialNumber = "";
else
meterSerialNumber = results[1];
if ((results[2].Length == 0))
customerID = "";
else
customerID = results[2];
if ((results[3].Length == 0))
meterCreditAmount = "";
else
meterCreditAmount = results[3];
if ((results[4].Length == 0))
debtInstallmentDeduction = "";
else
debtInstallmentDeduction = results[4];
if ((results[5].Length == 0))
vatOnEnergyAmount = "";
else
vatOnEnergyAmount = results[5];
if ((results[6].Length == 0))
vatOnDebt = "";
else
vatOnDebt = results[6];
if ((results[7].Length == 0))
outstandingDebtAmount = "";
else
outstandingDebtAmount = results[7];
if ((results[8].Length == 0))
tariffCategory = "";
else
tariffCategory = results[8];
if ((results[9].Length == 0))
tariffId = "";
else
tariffId = results[9];
if ((results[10].Length == 0))
encryptedToken1 = "";
else
encryptedToken1 = results[10];
if ((results[11].Length == 0))
encryptedToken2 = "";
else
encryptedToken2 = results[11];
if ((results[12].Length == 0))
encryptedToken3 = "";
else
encryptedToken3 = results[12];
if ((results[13].Length == 0))
encryptedToken4 = "";
else
encryptedToken4 = results[13];
if ((results[14].Length == 0))
systemMessage = "";
else
systemMessage = results[14];
if ((results[15].Length == 0))
customerMessage = "";
else
customerMessage = results[15];
if ((results[16].Length == 0))
predefinedMessage = "";
else
predefinedMessage = results[16];
if ((results[17].Length == 0))
transactionAcknowledgeNumber = "";
else
transactionAcknowledgeNumber = results[17];
What would be the best way to refactor this for acceptable coding standards? Would it be acceptable to make this a case statement instead?
This is not a case-wise execution so it can't be refactored to a switch-case. However it can be converted to functional code and then it factored out into a separate method so that the "ugly" part is hidden behind a method call.
Step#1 - Making the code functional
Here, we rewrite the code by following functional code writing practices. The rewritten code will look like:
customerName = (results[0].Length == 0) ? "" : results[0].Substring(18);
meterSerialNumber = (results[1].Length == 0) ? "" : results[1];
customerID = (results[2].Length == 0) ? "" : results[2];
meterCreditAmount = (results[3].Length == 0) ? "" : results[3];
debtInstallmentDeduction = (results[4].Length == 0) ? "" : results[4];
vatOnEnergyAmount = (results[5].Length == 0) ? "" : results[5];
.
.
.
transactionAcknowledgeNumber = (results[17].Length == 0) ? "" : results[17];
There are numerous advantages of writing the code this way. Important ones include:
terseness of code;
values being initialized at one place (by means of ternary operator) instead of two (one in if and another in else clause).
Step#2 - Factoring out the method
Now that the values are being initialized functionally, you can create a class (or you may be already having this class) containing the properties customerName, meterSerialNumber, ..., transactionAcknowledgeNumber. Either the constructor of the class can be designed to read the results and populate the class members or you may write a method to read the results. So it will look like:
ResultValues resultVal = new ResultValues();
resultVal.Read(results);
.
.
.
//Accessing the values later in the code
Print(resultVal.customerName);
...
PS:
1. I admit that ResultValues may not be a good class to make. Alternatively, you may create multiple classes by clubbing the related data and then have the Read() method of those classes read the values from results.
2. The essential idea of Step#2 is to factor out the "ugly" part to another simple and readable method call(s).