Moq: How to ensure Verify() reports on non-matching parameters - moq

I have the following unit test verification using Moq:
var mock = new Mock<IDoSomethingUseful>();
var sut = new Thingy(mock.Object);
sut.CallDoSomethingUseful();
mock.Verify(
somethingUseful => somethingUseful.Move(
It.Is<MyVector>(
myVector => myVector.x == 123)), Times.Once, "This fail message needs to be hard-coded with myVector.x was not equal to 123");
How can I get Verify() to tell me that the predicate match failed? The test runner only reports that the call failed so I need to rely on the hard-coded message.

Using Callback the invocation arguments can be accessed. See section Callbacks here.
In your case you could add an expected value for x to the test and get the actual value in Callback. Finally use an Assert to verify if expected and actual values equal where the message can be formated using both values. HTH
int expected_x_value = 123;
int actual_x_value = 0;
var mock = new Mock<IDoSomethingUseful>();
mock.Setup(m => m.Move(It.IsAny<MyVector>()))
.Callback<MyVector>(
(v) =>
{
actual_x_value = v.x;
}
);
var sut = new Thingy(mock.Object);
sut.CallDoSomethingUseful();
Assert.AreEqual(expected_x_value, actual_x_value,
string.Format("myVector.x was expected to be called with x = '{0}' but was '{1}'",
expected_x_value, actual_x_value));

Related

Cannot get Realm result for objects filtered by the latest (nsdate) value of a property of a collection property swift (the example is clearer)

I Have the following model
class Process: Object {
#objc dynamic var processID:Int = 1
let steps = List<Step>()
}
class Step: Object {
#objc private dynamic var stepCode: Int = 0
#objc dynamic var stepDateUTC: Date? = nil
var stepType: ProcessStepType {
get {
return ProcessStepType(rawValue: stepCode) ?? .created
}
set {
stepCode = newValue.rawValue
}
}
}
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
}
A process can start, processing , paused , resume (to be in step processing again), pause , resume again,etc. the current step is the one with the latest stepDateUTC
I am trying to get all Processes, having for last step ,a step of stepType processing "processing ", ie. where for the last stepDate, stepCode is 2 .
I came with the following predicate... which doesn't work. Any idea of the right perform to perform such query ?
my best trial is the one. Is it possible to get to this result via one realm query .
let processes = realm.objects(Process.self).filter(NSPredicate(format: "ANY steps.stepCode = 2 AND NOT (ANY steps.stepCode = 4)")
let ongoingprocesses = processes.filter(){$0.steps.sorted(byKeyPath: "stepDateUTC", ascending: false).first!.stepType == .processing}
what I hoped would work
NSPredicate(format: "steps[LAST].stepCode = \(TicketStepType.processing.rawValue)")
I understand [LAST] is not supported by realm (as per the cheatsheet). but is there anyway around I could achieve my goal through a realm query?
There are a few ways to approach this and it doesn't appear the date property is relevant because lists are stored in sequential order (as long as they are not altered), so the last element in the List was added last.
This first piece of code will filter for processes where the last element is 'processing'. I coded this long-handed so the flow is more understandable.
let results = realm.objects(Process.self).filter { p in
let lastIndex = p.steps.count - 1
let step = p.steps[lastIndex]
let type = step.stepType
if type == .processing {
return true
}
return false
}
Note that Realm objects are lazily loaded - which means thousands of objects have a low memory impact. By filtering using Swift, the objects are filtered in memory so the impact is more significant.
The second piece of code is what I would suggest as it makes filtering much simpler, but would require a slight change to the Process model.
class Process: Object {
#objc dynamic var processID:Int = 1
let stepHistory = List<Step>() //RENAMED: the history of the steps
#objc dynamic var name = ""
//ADDED: new property tracks current step
#objc dynamic var current_step = ProcessStepType.created.index
}
My thought here is that the Process model keeps a 'history' of steps that have occurred so far, and then what the current_step is.
I also modified the ProcessStepType enum to make it more filterable friendly.
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
//this is used when filtering
var index: Int {
switch self {
case .created:
return 0
case .scheduled:
return 1
case .processing:
return 2
case .paused:
return 3
case .finished:
return 4
}
}
}
Then to return all processes where the last step in the list is 'processing' here's the filter
let results2 = realm.objects(Process.self).filter("current_step == %#", ProcessStepType.processing.index)
The final thought is to add some code to the Process model so when a step is added to the list, the current_step var is also updated. Coding that is left to the OP.

Add "blocking" to Swift for-loop

I am using Swift in a project, and using SQLite.swift for database handling. I am trying to retrieve the most recent entry from my database like below:
func returnLatestEmailAddressFromEmailsTable() -> String{
let dbPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
let db = Database("\(dbPath)/db.sqlite3")
let emails = db["emails"]
let email = Expression<String>("email")
let time = Expression<Int>("time")
var returnEmail:String = ""
for res in emails.limit(1).order(time.desc) {
returnEmail = res[email]
println("from inside: \(returnEmail)")
}
return returnEmail
}
I am trying to test the returned string from the above function like this:
println("from outside: \(returnLatestEmailAddressFromEmailsTable())")
Note how I print the value from both inside and outside of the function. Inside, it works every single time. I am struggling with the "from outside:" part.
Sometimes the function returns the correct email, but sometimes it returns "" (presumably, the value was not set in the for loop).
How can I add "blocking" functionality so calling returnLatestEmailAddressFromEmailsTable() will always first evaluate the for loop, and only after this return the value?

Moq SetupSet on property

i am trying to learn to use Moq (4) to test the C# code below. I was hoping that by setting
mockTimer.SetupSet(m => m.Interval = It.IsInRange(
interval - shorter, interval + longer, Range.Inclusive));
before calling the method which assigns the interval property a value (ageService.AddParticipant method), the test would throw when an incorrect value was assigned. However, even when a value well outside the specified range is assigned to the Interval property within the AddParticipant method, the test passes. I also find timer.Interval has a value of 0 after executing the AddParticipant method, even though I can see this property being assigned a non-zero value when stepping through the AddParticipant method.
[TestMethod]
public void TestAgeUpdatingStartOnAdd()
{
var mockTimer = new Mock<IDispatcherTimer>();
mockTimer.SetupProperty(m => m.Interval);
mockTimer.Setup(m => m.Start());
mockTimer.Setup(m => m.Stop());
IDispatcherTimer timer = mockTimer.Object;
var ageService = new AgeUpdatingService(timer);
TimeSpan interval = TimeSpan.FromMinutes(10);
TimeSpan tolerance = TimeSpan.FromMilliseconds(100)
mockTimer.SetupSet(m => m.Interval = It.IsInRange(
interval - tolerance, interval + tolerance, Range.Inclusive));
ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval });
What am I doing wrong? Am I missing the point of the SetupSet method all together (and therefore should just stick to examining the properties on the timer object after executing the function, which seemed to work prior to placing the SetupSet method in the code)? If so, could you please explain what SetupSet exists for. Thank you.
Since you're creating your mock with new Mock<IDispatcherTimer>(), it defaults to Loose mock behavior. This means that the mock object will not complain when it is used in a way that was not specified via a Setup method. Using the constructor overload that accepts a MockBehavior enumeration and specifying Strict will make the code behave like you'd expect. It looks like that's how you're expecting to use it judging by the Setup calls; they would be unnecessary if you were using loose mocks.
Alternatively you can keep the loose mock and change the SetupSet for the Interval to be a VerifySet after you expect it to be set. I.e.:
var ageService = new AgeUpdatingService(timer);
TimeSpan interval = TimeSpan.FromMinutes(10);
TimeSpan tolerance = TimeSpan.FromMilliseconds(100)
ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval });
mockTimer.VerifySet(m => m.Interval = It.IsInRange(
interval - tolerance, interval + tolerance, Range.Inclusive));
This is like a test assertion, meaning if a set of the Interval property never happened when this is invoked, it would throw a MoqException and fail the test.
SetupSet can be used to setup a property setter - it is fairly unusual to need this, as arguments passed to Set typically don't need to be captured, as the calls to the Setter can be verified with a VerifySet after the "Act" step.
Here's a way to achieve what you want:
var mockTimer = new Mock<ITimer>();
// Simulate the actions of the Sut with the Mock
mockTimer.Object.Interval = 6;
mockTimer.Object.Interval = 7;
mockTimer.Object.Interval = 999;
// Ensure the mock was called in-band
mockTimer.VerifySet(m => m.Interval = It.IsInRange(5, 10, Range.Inclusive),
Times.Exactly(2));
// Ensure the mock was not called out of band
mockTimer.VerifySet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10),
Times.Never);
Another, less elegant approach would be to use SetupSet to detect invalid invocations directly:
mockTimer.SetupSet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10))
.Throws(new ArgumentOutOfRangeException());

EF - taking X elements after a specific element in a sorted query

A Chat has Messages. Given a MessageId, I'm trying to get the next 50 messages. What I have now should work in theory, but it's very inefficient as I'm loading everything into memory. Here's what I have so far:
// get message with parent chat / other messages
var message = db.ChatMessages.Include(s => s.Chat.Messages).First(s => s.ChatMessageId == messageId);
var chat = message.Chat;
// this is what I want to avoid, but I don't know how to get the position without throwing all messages into memory
var messages = chat.Messages.OrderByDescending(s => s.DatePosted).ToList();
var index = messages.IndexOf(message);
messages = messages.GetRange(index, index + 50);
return messages.ToList();
How can I perform this operation without throwing every message into memory?
If you get the Id of the last message (or something else unique), this becomes simpler. Assuming the Ids are always incrementing...
var messages = chat.Messages.
Where(s=>s.Id > LastMessage.Id).
OrderByDescending(s => s.DatePosted).
Take(50);
If you don't have always incrementing Ids...
var messages = chat.Messages.
Where(s=>s.DatePosted > LastMessage.DatePosted).
OrderByDescending(s => s.DatePosted).
Take(50);
return messages.ToList();

global variable not getting set with proper values in another function in flex

I have a global variable 'csId' of string type. In the code below under drawChart() function, in for loop, csID variable should be set to '1' by the modelLocator when i=0 and csId should be set to '2' by modelLocator when i=1.(considering lengh=2).
Alert in drawchart() (for csId) seems to be printing the right 'csid' values(both 1 and 2) but in the dataFunction() 'columnSeries_labelFunc' i am always getting the csId Alert value as '2' and never as '1'.
Please find the code below:
drawchart() function::
public function drawChart():void
{
var cs:ColumnSeries= new ColumnSeries();
var lenght:Number=AppModelLocator.getInstance().ctsModel.productSummary.getItemAt(0).collMgmtOfcList.length;
myChart.series = [cs];
var tempObj:Object;
for(csLoop=0;csLoop<lenght;csLoop++)
{
cs = new ColumnSeries();
this.csId= new String(String(AppModelLocator.getInstance().ctsModel.productSummary.getItemAt(0).collMgmtOfcList[csLoop]));
Alert.show("csId="+this.csId);
cs.id=this.csId;
cs.displayName = 'Exposure';
cs.dataFunction=columnSeries_labelFunc;
myChart.series[csLoop] = cs;
}
columnSeries_labelFunc() function::
private function columnSeries_labelFunc(series:Series, item:Object, fieldName:String):Object {
var col:Number=0;
Alert.show("value of csid in columnSeries_labelFunc="+this.csId);
if(fieldName == "yValue" && series.id==csId){
return(item.exposureUSDList[0]);
}else if(fieldName == "yValue" && series.id==csId) {
return(item.exposureUSDList[1]);
}else if(fieldName == "xValue"){
return(item.rptType);
}else
return null;
}
Please Help!!!
First: Assigning a value to a global variable repeatedly inside a loop is a bad idea. Nothing good will happen from that.
It's hard to tell from the context here, but the most likely reason that you're having this problem is that the flow of execution is as follows:
drawChart() executes synchronously, counting through each step in the loop, creating the ColumnSeries, which are each invalidated, meaning they will redraw on the next frame. The function ends, with csID at the last value it held.
The app goes into the next step in the elastic racetrack and validates the invalidated components.
columnSeries_labelFunc is called, with csID still holding the terminal value from the loop.
The end result being that columnSeries_labelFunc isn't called until you're already completely finished in drawChart.
The simplest fix would be to read the id that you're setting on the series in the label function, rather than relying on a global variable at all.

Resources