I have a mocked executor that Asserts the unit after x amount of callbacks depending on what values we give to the parameters. Here's a sample code of my unit test
[Test]
[TestCase("foo", false, 2)]
[TestCase("foo", true, 3)]
public void CommandLineShouldBeValidTest(string parameter1, bool parameter2, int finalCallbackCounter)
{
int initialCallbackCounter = 0;
var executorMock = new Mock<ITaskExecutor>();
executorMock.Setup(m => m.Execute(It.IsAny<IExecutionContext>(), It.IsAny<ITask>()))
.Callback<IExecutionContext, ITask>((c, it) =>
{
var p = (ProcessTask)it;
initialCallbackCounter++;
if (initialCallbackCounter == finalCallbackCounter)
{
Assert.AreEqual(expectedCommandLine, p.CommandLine);
}
});
var macro = new Macro(parameter1, parameter2, executorMock.Object);
macro.Execute();
}
For the moment I'm using the finalCallbackCounter parameter for it, so for example if I make the second boolean parameter true instead of false, I need to change it to 3 (I actually have more arguments and cases in my current code, I just simplified it for the question's purpose).
This way to do it feels really finnicky and not very futureproof. Is there a more elegant solution to this problem?
You could capture the ITasks, then assert at the end.
Setup is not intended for assertions:
var capturedTasks = new List<ITask>();
var executorMock = new Mock<ITaskExecutor>();
executorMock.Setup(m => m.Execute(
It.IsAny<IExecutionContext>(),
Capture.In(capturedTasks)));
var macro = new Macro(mock.Object);
macro.Execute();
if (capturedTasks.Count >= finalCallbackCounter)
{
var p = (ProcessTask)capturedTasks[finalCallbackCounter - 1];
Assert.AreEqual(expectedCommandLine, p.CommandLine);
}
Related
i have a test where i will be comparing two objects.
i am open to know whats the best way to do it.
i have created something for which i have an issue that needs help.
following code has an object property that needs to be present
i would like to assert that all fields to be present except the id property.
i feel like the last 5 statements feel inappropriate, if there is a clearer way of doing it, i would like to know.
[Fact]
public void CreateTransaction_AddFirstTransaction_ShouldUpdateTransactionJson()
{
// Arrange
var mockFileSystem = new MockFileSystem();
var buyCrypto = new BuyCrypto(mockFileSystem);
var bitcoin = new Currency()
{
name = "bitcoin",
code = "btc",
price = 10
};
// Act
buyCrypto.CreateTransaction(true, bitcoin, 10);
//Assert
var result = JsonSerializer
.Deserialize<List<Transaction>>(mockFileSystem.GetFile(TransactionJson).TextContents);
Assert.Equal("bitcoin", result[0].currency);
Assert.Equal(DateTime.Now.ToString(), result[0].dateTime);
Assert.Equal("TestName", result[0].name);
Assert.Equal(10, result[0].quantity);
Assert.Equal(100, result[0].total);
}
I love using Fluent Assertions for these kinds of tests (docs). You could do something like this:
// Arrange
// ... other stuff
var expectedTransaction = new Transaction {
currency = "bitcoin",
dateTime = DateTime.Now.ToString(),
name = "TestName",
quantity = 10,
total = 100 };
// Act
// ...
// Assert
result[0].Should().BeEquivalentTo(expectedTransaction, options => options.Excluding(t => t.Id));
This may not be something that's even possible but I thought I'd ask anyway. Is there anyway for me to stub out this method so that the second call is also stubbed out using the parameter provided in the method I'm testing?
The method to stub:
public SupportDetails GetSupportDetails(string languageKey)
{
var result = FindSupportDetails(languageKey);
return result ?? FindSupportDetails("en-us");
}
My Current test:
public void GetsUSDetails_IfLangKeyDoesNotExist()
{
var langKey = "it-it";
_repo.Stub(s => s.FindSupportDetails(langKey))
.Return(supportDetails.Where(sd => sd.LanguageKey == langKey)
.SingleOrDefault());
ISupportRepository repo = _repo;
var actual = repo.GetSupportDetails(langKey);
Assert.AreEqual("en-us", actual.LanguageKey);
}
and the supportDetails object used in the test:
supportDetails = new SupportDetails[]
{
new SupportDetails()
{
ContactSupportDetailsID = 1,
LanguageKey = "en-us"
},
new SupportDetails()
{
ContactSupportDetailsID = 2,
LanguageKey = "en-gb"
},
new SupportDetails()
{
ContactSupportDetailsID = 3,
LanguageKey = "es-es"
}
};
The correct and the most elegant solution to your problem is to use Do method:
_repo.Stub(s => s.FindSupportDetails(null))
.IgnoreArguments()
.Do((Func<string, SupportDetails>)
(langKey => supportDetails.SingleOrDefault(sd => sd.LanguageKey == langKey)));
The Func will raise no matter what argument was passed to FindSupportDetails, then the correct SupportDetails will select.
I am trying to write a method that takes an IConnectableObservable, does some processing on it and returns a new IConnectableObservable that streams the processed data plus some additional items. The sequence being streamed is finite, but it has side effects so it needs to be run only once. However, I am trying to do two things with it:
Transform each element in the stream using a Select query.
Collect each element in the stream into an array and do some processing on the array and stream the results.
Below is my best attempt at doing this, but I feel that there probably is a superior way of doing this that I haven't figured out.
protected override IConnectableObservable<ITestResult<ITestOutput<double, double>, ITestLimit<double>>> ProcessOutput(
IConnectableObservable<ITestOutput<double, double>> output, InputVerificationTestCase testCase)
{
var obsResults = output.Select(o =>
{
var limits = GenerateDcAccuracyLimits.CalculateAbsoluteLimits(o.Input, testCase.FullScaleRange, testCase.Limits);
return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
{
Component = "Variable Gain Module Input",
Description = "Measurement Accuracy",
Limits = limits,
Output = o,
Passed = _validationService.Validate(o.Result, limits)
};
});
var observable = Observable.Create<ITestResult<ITestOutput<double, double>, ITestLimit<double>>>(obs =>
{
var resultTask = obsResults.ForEachAsync(obs.OnNext);
var fitTask = output.ToArray().ForEachAsync(arr =>
{
resultTask.Wait();
var fit = ComputeErrorFit(arr, testCase);
obs.OnNext(GetGainErrorResult(fit.Item2, testCase));
});
output.Connect();
Task.WaitAll(resultTask, fitTask);
obs.OnCompleted();
return Disposable.Empty;
});
return observable.Publish();
}
Edited 10/7/2015:
Here is the rest of the code:
private ITestResult<ITestOutput<double, double>, ITestLimit<double>> GetGainErrorResult(double gainError, InputVerificationTestCase testCase)
{
var gainErrorLimit = GenerateDcAccuracyLimits.CalculateGainErrorLimits(testCase.FullScaleRange, testCase.Limits);
return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
{
Component = "Variable Gain Module Input",
Description = "Gain Error",
Passed = _validationService.Validate(gainError, gainErrorLimit),
Output = new TestOutput<double, double> { Input = 0, Result = gainError },
Limits = gainErrorLimit
};
}
private Tuple<double, double> ComputeErrorFit(ITestOutput<double, double>[] outputs, InputChannelTestCase testCase)
{
var input = outputs.Select(o => o.Input);
var vErr = outputs.Select(o => o.Result - o.Input);
return Fit.Line(input.ToArray(), vErr.ToArray());
}
Also in an abstract base class, I have the following:
public IConnectableObservable<TOutput> RunSingleChannel(TCase testCase)
{
dut.Acquisition.SampleRate.Value = SampleRate;
dut.AnalogChannels[testCase.Channel].InputRange.Value = testCase.FullScaleRange;
var testOutput = CreateTestProcedure(testCase.Channel).RunAsync(testCase.InputVoltages);
return ProcessOutput(testOutput.Replay(), testCase);
}
protected abstract IConnectableObservable<TOutput> ProcessOutput(IConnectableObservable<ITestOutput<double, TAcq>> output, TCase testCase);
It seems that you're going about doing things the hard way with Rx. You really need to avoid mixing in Tasks with Observables. They make your code hard to reason about and often lead to deadlocks and other concurrency issues.
You should try something like this instead:
protected override IConnectableObservable<ITestResult<ITestOutput<double, double>, ITestLimit<double>>> ProcessOutput(
IConnectableObservable<ITestOutput<double, double>> output, InputVerificationTestCase testCase)
{
var source = output.RefCount();
return
source
.Select(o =>
{
var limits = GenerateDcAccuracyLimits.CalculateAbsoluteLimits(o.Input, testCase.FullScaleRange, testCase.Limits);
return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
{
Component = "Variable Gain Module Input",
Description = "Measurement Accuracy",
Limits = limits,
Output = o,
Passed = _validationService.Validate(o.Result, limits)
};
})
.Merge(
source
.ToArray()
.Select(arr => GetGainErrorResult(ComputeErrorFit(arr, testCase).Item2, testCase)))
.Publish();
}
It's a little odd that you're using connectable observables, but the above should roughly be doing what you need.
I've tested the code using this sample:
public IConnectableObservable<int> ProcessOutput(IConnectableObservable<int> output)
{
var source = output.RefCount();
return
source
.Merge(source.ToArray().Select(arr => arr.Sum()))
.Publish();
}
void Main()
{
var output = Observable.Range(1, 10).Publish();
var processed = ProcessOutput(output);
processed.Subscribe(x => Console.WriteLine(x));
processed.Connect();
}
Which outputs:
1
2
3
4
5
6
7
8
9
10
55
I've also checked that the original observable values are only produced once.
Apologies I haven't done very well with the title of the question, hopefully it will be apparenent with some code
I've created a class that stores poker hand information as follows
public class BestHandSummary<T>
{
public Func<T, bool> Test { get; set; }
public Ranking Rank { get; set; } //Enum: Nothing, TwoPair, Straight, Flush, Poker :in ascending order
public int BestCard { get; set; }
public BestHand(Ranking r)
{
Rank = r;
}
..//default ctor
}
I initialised the rules collection in order of most valuable hand so that when I take the First() of the matched rules the most powerful hand will be chosen as best hand.
rules = new List<BestHandSummary<PokerHand>>()
{
new BestHandSummary<PokerHand> { Test = h => h.HandContainsFourOfAKind(out bestCard),
Rank = Ranking.FourOfAKind,
BestCard = bestCard },
new BestHandSummary<PokerHand> { Test = h => h.HandContainsFlush(),
Rank = Ranking.Flush },
new BestHandSummary<PokerHand> { Test = h => h.HandContainsStraight(out bestCard),
Rank = Ranking.Straight,
BestCard = bestCard },
new BestHandSummary<PokerHand> { Test = h => h.HandContainsTwoPair(out bestCard),
Rank = Ranking.Straight,
BestCard = bestCard },
};
private BestHandSummary<PokerHand> GetAPlayersBestHand(PokerHand hand)
{
bool hasAny = rules.Any(r => r.Test(hand));
if (hasAny)
{
return rules.Where(r => r.Test(hand) == true).First();
}
return new BestHandSummary<PokerHand>(Ranking.Nothing);
}
What I can't seem to figure out is how can I tunnel the out param bestCard into the BestCard property of the BestHandSummary class? The code above doesn't work, BestCard = bestCard doestn't get assigned, which I can understand why, but I'm wondering if there is any small change I can make to fix it..
int bestCard;
new BestHand<PokerHand> { Test = h => h.HandContainsFourOfAKind(out bestCard),
Rank = Ranking.FourOfAKind,
BestCard = bestCard },
This code won't work, because HandContainsFourOfAKind was never called, and so nothing was assigned to bestCard.
I'm only interested in bestCard when the rule matched. It is used for when there is a draw between two players. E.G. H= 22KJJ -> best card is Jack, not king
So, you want BestCard to be assigned only when Test is invoked? This will do.
var hand = new BestHand<PokerHand> {Rank = Ranking.FourOfAKind};
hand.Test = h =>
{
int bestCard; //var local to the lambda's scope
bool contains = h.HandContainsFourOfAKind(out bestCard);
hand.BestCard = bestCard;
return contains;
};
I've written an equalizer myself a few years ago. I don't have a direct answer to your question, but one thing comes to my mind:
In your example, if you just look at the best card involved building the rank like the Jack in the two-pair hand, you won't figure out the best hand, if both have the same two-pair with different kicker. You might have to use a third method on that.
Maybe you are better of to do this in one piece. I solved this with an if-monster, which returned an exact long-value, indicating every card in it's value for that hand.
I am trying to test a C# method that uses a dynamic property from a C++/CLI wrapper.
The interface I am trying to mock is
property Object^ DynamicValueItem
{
[returnvalue: System::Runtime::CompilerServices::DynamicAttribute]
Object^ get () ;
}
The method I am trying to test is
public void GetBillInfo (IConfigurationItem item)
{
dynamic ValueItem = item.DynamicValueItem;
string Curr = ValueItem.Currency;
string Ser = ValueItem.BillSeries;
}
My test method is
[TestMethod()]
public void GetBillInfoTest()
{
BnrHelperMethods target = new BnrHelperMethods();
var ValueItem = new
{
Currency = "USD",
BillValue = 100,
};
var mockItem = new Mock<IConfigurationItem>();
mockItem.Setup(i => i.DynamicValueItem).Returns(ValueItem);
target.GetBillInfo(mockItem.Object);
}
I got the method for mocking the dynamic property from http://blogs.clariusconsulting.net/kzu/how-to-mock-a-dynamic-object/
The example was for a standard C# dynamic property so I have had to adapt my C++/CLI property to try and get the same effect.
My problem is that when I perform the test I get a RuntimeBinderException stating that the object does not contain the definition of for Currency. If I look at the Locals window it shows both Currency and BillValue
-ValueItem { Currency = USD, BillValue = 100 }
dynamic{<>f__AnonymousType1}
-BillValue 0x00000064 int
-Currency "USD" string
When using the method normally it works. The only difference I see is that Currency and BillValue are under a Dynamic View item in the Local window
-ValueItem {} dynamic {MEIConfiguration.ConfigurationValueItem}
-Dynamic View Expanding the Dynamic View will get the dynamic members for the object
-BillValue 0x000003e8 System.Int32
-Currency "GBP" System.String
Have I defined the C++/CLI property correctly?
Am I creating the mock correctly?
Can anyone tell me what I am doing wrong?
For anyone who is interested here is the solution provided by a colleague.
[TestMethod()]
public void GetBillInfoTest()
{
BnrHelperMethods target = new BnrHelperMethods();
dynamic valueItem = new ExpandoObject();
valueItem.Currency = "USD" ;
valueItem.BillValue = 100;
var mockItem = new Mock<IConfigurationItem>();
mockItem.Setup(i => i.DynamicValueItem).Returns ((object)valueItem);
target.GetBillInfo(mockItem.Object);
}