Simple Moq ? - Problem with .Verify - moq

just a simple question here. I've used Moq for awhile but, as of yet, have only used it for stubbing and not for mocking. I am trying to introduce our developers to unit testing. I set up a simple example to explain the concepts but i can't seem to get it working. Probably something simple so i thought i would just ask you all to see what i'm doing wrong:
<Test()> _
Public Sub Divide_DivideByZero_LogsError()
Dim mock = New Mock(Of ILogger)
With mock
Dim calc = New MyCalculator(New CalculatorData, .Object)
calc.Divide(55, 0)
.Verify(Function(x) CType(x,ILogger).WriteError(it.IsAny(of String),It.IsAny(Of String))))
End With
End Sub
I'm using Moq version 3.2.416.3. I get an error on the .verify telling me that i'm calling it with incorrect arguments. I'm just trying to verify that .WriteError was called. any help would be appreciated.
Edit:
Ok everyone, if i change ".WriteError" from a sub (void return) to a function that returns a boolean it works. WriteError doesn't really need to be a function. Does anyone know why a sub wouldn't work?

Edit: Ok everyone, if i change ".WriteError" from a sub (void return) to a function that returns a boolean it works. WriteError doesn't really need to be a function. Does anyone know why a sub wouldn't work?
As far, as I remember, VB9 does not support anonymous Subs (only Functions) and it's a serious show-stopper for Moq usage in VB.net.
So, as soon, as you have changed WriteError signature from Sub to Function, compiler have successfully resolved return type for anonymous function in Verify parametrer.

I think you need to make it Verifiable() before actually calling Verify(). I'm not sure if it can do automatic verifiability though.
And IMHO I find using VerifyAll() much easier than verifying individual methods. i.e.:
mock.Setup(Function(x) CType(x, ILogger).WriteError(It.IsAny(Of String), It.IsAny(Of String))) _
.Verifiable()
mock.Object.WriteError("test", "Test")
mock.VerifyAll()
Not sure if I get all the method names/signature right though but you should get the idea.

Related

.NET getting a ThreadStateException

Hello I am getting an error on the following line:
If Not System.Windows.Clipboard.GetDataObject Is Nothing Then
I believe it would look something like this in C#
if (System.Windows.Clipboard.GetDataObject!=null) {
The Error is:
"ThreadStateException: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made."
Can anyone tell me how to fix this? A few suggestions online mentioned adding <STAThread()> _ over the 'main' method, however, this is an ASP.NET controller method, I tried adding this over it and it didn't help. Anyone have any suggestions?
ASP.NET doesn't really get along with STAThread.
You need an additional task scheduler to run a thread in STA mode to access what you want from the operating system
Take a look at this article it got me going with something like this.
Also, keep in mind that multiple request to your page might mess up things, since you're interacting with the clipboard of the operating system (which runs in another COM context) son concurrency might by risky.
What are you trying to acomplish, maybe there is a better way.
Don't forget to read the final notes.
http://www.telerik.com/community/forums/community-forums/interesting-resources/using-clipboard-class-in-asp-net.aspx
It seems that this can be caused by an out of date dll in your /bin directory. Have you tried clearing it?
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/
http://www.devnewsgroups.net/windowsforms/t36723-current-thread-must-set-single-thread-apartment-sta.aspx
Also, you can explicitly start up a new thread in Single Apartment Mode
imports System.Threading
dim newThread As New Thread(new ThreadStart(AddressOf ThreadMethod))
newThread.SetApartmentState(ApartmentState.STA);
newThread.Start();
'and elsewhere
Public Sub ThreadMethod()
If Not System.Windows.Clipboard.GetDataObject Is Nothing Then
'stuff
End if
End Sub

Dictionary Behaves Strangely During Databinding

I was trying to do a little data access optimization, and I ran into a situation where a dictionary appeared to get out of sync in a way that should be impossible, unless I'm somehow getting into a multithreaded situation without knowing it.
One column of GridLabels binds to a property that does data access -- which is a tad expensive. However, multiple rows end up making the same call, so I should be able to head any problems off at the pass by doing a little caching.
However, elsewhere in the app, this same code is called in ways where caching would not be appropriate, I needed a way to enable caching on demand. So my databinding code looks like this:
OrderLabelAPI.MultiSyringeCacheEnabled = True
Me.GridLabels.DataBind()
OrderLabelAPI.MultiSyringeCacheEnabled = False
And the expensive call where the caching happens looks like this:
Private Shared MultiSyringeCache As New Dictionary(Of Integer, Boolean)
Private Shared m_MultiSyringeCacheEnabled As Boolean = False
Public Shared Function IsMultiSyringe(orderLabelID As Integer) As Boolean
If m_MultiSyringeCacheEnabled Then
'Since this can get hit a lot, we cache the values into a dictionary. Obviously,
'it goes away after each request. And the cache is disabled by default.
If Not MultiSyringeCache.ContainsKey(orderLabelID) Then
MultiSyringeCache.Add(orderLabelID, DoIsMultiSyringe(orderLabelID))
End If
Return MultiSyringeCache(orderLabelID)
Else
Return DoIsMultiSyringe(orderLabelID)
End If
End Function
And here is the MultiSyringeCacheEnabled property:
Public Shared Property MultiSyringeCacheEnabled As Boolean
Get
Return m_MultiSyringeCacheEnabled
End Get
Set(value As Boolean)
ClearMultiSyringeCache()
m_MultiSyringeCacheEnabled = value
End Set
End Property
Very, very rarely (unreproducably rare...) I will get the following exception: The given key was not present in the dictionary.
If you look closely at the caching code, that's impossible since the first thing it does is ensure that the key exists. If DoIsMultiSyringe tampered with the dictionary (either explicitly or by setting MultiSyringeCacheEnabled), that could also cause problems, and for awhile I assumed this had to be the culprit. But it isn't. I've been over the code very carefully several times. I would post it here but it gets into a deeper object graph than would be appropriate.
So. My question is, does datagridview databinding actually get into some kind of zany multithreaded situation that is causing the dictionary to seize? Am I missing some aspect of shared members?
I've actually gone ahead and yanked this code from the project, but I want to understand what I'm missing. Thanks!
Since this is ASP.NET, you have an implicit multithreaded scenario. You are using a shared variable (see What is the use of a shared variable in VB.NET?), which is (as the keyword implies) "shared" across multiple threads (from different people visiting the site).
You can very easily have a scenario where one visitor's thread gets to here:
'Since this can get hit a lot, we cache the values into a dictionary. Obviously,
'it goes away after each request. And the cache is disabled by default.
If Not MultiSyringeCache.ContainsKey(orderLabelID) Then
MultiSyringeCache.Add(orderLabelID, DoIsMultiSyringe(orderLabelID))
End If
' My thread is right here, when you visit the site
Return MultiSyringeCache(orderLabelID)
and then your thread comes in here and supercedes my thread:
Set(value As Boolean)
ClearMultiSyringeCache()
m_MultiSyringeCacheEnabled = value
End Set
Then my thread is going to try to read a value from the dictionary after you've cleared it.
That said, I am not sure what performance benefit you expect from a "cache" that you clear with every request. It looks like you should simply not make this variable shared- make it an instance variable- and any user request accessing it will have their own copy.

Which function is faster and efficient?

I need to verify if a certain user exist on my asp.net site.I want to know if which of these two functions is more efficient, faster and better compared to each other and why.Thanks in advance!
Public Function CheckIfFriendExist(ByVal arg As String) As Boolean
Dim alluser As New MembershipUserCollection()
alluser = Membership.GetAllUsers()
For Each user As MembershipUser In alluser
If user.UserName.ToLower() = arg.ToLower() Then
Return True
Exit For
End If
Next
Return False
End Function
or
Public Function CheckIFFriendExist2(ByVal arg As String) As Boolean
Dim x As Integer = 0
Dim themember As MembershipUserCollection = Membership.FindUsersByName(arg, 0, 1, 1)
For Each member As MembershipUser In themember
x = x + 1
Next
If x > 0 Then
Return True
Else
Return False
End If
End Function
First comment - get rid of the pointless instantiation when you declare allUser in your first block - change
Dim alluser As New MembershipUserCollection()
to
Dim alluser As MembershipUserCollection
It's impossible to answer the rest without knowing about the membership provider in user and the implementation of the method. Have you tried just timing it?
Generally speaking, the second option has the better potential for performance. The actual effect depends on which membership provider you are using, but in the second case any implementation can take advantage of any internal indexing mechanisms if they are present, and potentially less data needs to be retrieved and transferred because you're only getting at most one MembershipUser due to the paging.
Theoretically, the first option could be faster than the second, but that would mean the membership provider implementation really sucks :)
You appear to be counting the number of members in the collection, but you merely need to know if there is at least one member in the collection. Thus counting is not actually necessary. Also, what is wrong with using the Count property? I'm not saying this for optimization purposes since the impact will be minimal, but I think the intent of your code would be clearer if written that way.
Public Function CheckIFFriendExist2(ByVal arg As String) As Boolean
Dim foundMembers As MembershipUserCollection = _
Membership.FindUsersByName(arg, 0, 1, 1)
Return foundMembers.Count > 0
End Function
Alternatively, use Membership.GetUser to retrieve a single user by name. After all, I wouldn't recommend implementing a membership provider that allows for multiple users with the same name.
Which function is better in terms of readability:
I don't remember visual basic too well, but in the second function, isn't there a way to check themember to see whether it's empty directly, instead of having to loop through it? Some kind of method name like "IsEmpty".
Assuming that there is, you can change the code in the second example to just 2 lines:
Dim themember As MembershipUserCollection = Membership.FindUsersByName(arg, 0, 1, 1)
' Check if themember is empty, return true or false appropriately
In that case, the second function will be much better in the sense that it's easier to read.
Which function is better in terms of efficiency:
It's impossible to even guess without knowing the details of FindUsersByName or GetAllUsers, but I would guess the second function is faster (since it offloads the work to a specific function designed for it).
However, this is a very crude guess. The only proper way to answer this question is to implement the two and run tests on both, to find out which is faster.
In any case, the difference is unlikely to be enough to matter, but if you really care, you definitely have to time each solution.
Usually the easiest way to answer questions of this type ("which is faster"), is to simply measure it.
.NET har a built-in class for this purpose, System.Diagnostics.Stopwatch:
Dim stopwatch As New System.Diagnostics.Stopwatch
stopwatch.Start()
For i = 0 To 10000
MethodThatMightJustTakeTooLong()
Next i
stopwatch.Stop()
Console.Writeline(Elapsed)
I would go with the second function with a few modifications.
Instead of using FindUsersByName, try GetUser -- this is more correct as you are looking for one user.
Then, check the count property of the user.
Dim user = Membership.GetUser(arg)
If user = 1 Then
Return True;
Else
Return False;
End If
I don't really know Visual Basic, but I'm sure that if statement could be simpler, something like return (user === 1) ? true : false in other languages.
The performance of these functions are not going to make a noticeable difference until you have hundreds of thousands of users for the application.
My suggestion is to stop micro-optimizing unless you have identified this as a problem area through profiling.

Error handling using events, checking if an error happened and react accordingly

I have an object, say Order where if an error occurs, it raises the ErrorOccurred event. If I'm running some code in say, the codebehind for a .aspx page with an public Order registered as WithEvents and I want to check to see if an error has occurred before I run more code, how do I do this? I can't simply check theOrder.ErrorOccurred. Do I have to create a local boolean flag that switches over in the event handler (OnErrorOccurred)? Or is there a better way to do this?
Thanks!
Example:
Public WithEvents theOrder As New Order
Public Sub DoStuff()
theOrder.DoSomething()
If theOrder.ErrorOccurred Then
do stuff
End If
End Sub
That seems like a reasonable approach. If there is lots of logic going on with an Order object that depends on knowing about errors, having a Status field would allow easy communication to any consumer what the status of the order was, rather than everyone having to subscribe to the event and track it themselves.
Alternately you could track it internally in the Order and just throw exceptions when critical methods were accessed if the Order was in an error state. This has the disadvantage of making you do more error handling, but would have the advantage of making sure that any Order consumer handled them explicitly.
Why not use structured error handling?
Try
'Code that may raise an error.
Catch
'Code to handle the error.
Finally
'Code to do any final clean up.
End Try
http://support.microsoft.com/kb/315965
This is what it is intended for.
Problems may arize if someone calls DoSomething but thay are unaware that they need to check theOrder.ErrorOccurred. based on what DoSomething is doing, allowing one to call a method and letting it fail quietly can be a problem.
If do something is doing logging sure, let it fail. If it is finalizing an order process..
Brian
Use the Try Catch Block
Try
'try your code here
Catch somevariablenamehere As Exception
'use methods from Exception class to get to know the error better and how to deal with it
Finally
'this is optional, If you want to do something finally, like cleaning up etc. You can do here
End Try
'to end the Try block

InsertOnSubmit not triggering a database insert on SubmitChanges

I'm experiencing an odd scenario and I'm looking for ways to figure out what's going wrong. I've got a piece of code that inserts a row into a table - the kind of thing I've done in dozens of other apps - but the end result is nothing happens on the database end, and no errors are generated. How do I find out what's going wrong?
Here's my code:
Partial Class MyDatabaseDataContext
Public Sub CreateEnrollee(subId, depId)
dim newEnrollee = New enrolee With {.subId = subId, .depId = depId}
Me.enrollees.InsertOnSubmit(newEnrollee)
Me.SubmitChanges()
dim test = NewEnrollee.id '<-- auto-incrementing key'
End Sub
End Class
After SubmitChanges is called, no new row is created, and "test" is zero. No errors are generated. I have no idea why it's not trying to insert the row. Any ideas on how to debug this?
You could enable logging:
Me.Log = Console.Out;
You could check the ChangeSet for your object.
FOUND IT! Part of the debugging I did for some other issues included adding some logging to some of the extensibility methods:
Partial Private Sub InsertEnrollee(instance As Enrollee)
End Sub
I thought "InsertEnrollee" existed so I could perform actions after the Enrollee was inserted, so I added logging code here and that's when the trouble started. Now I'm guessing this is how you would override the Enrollee insert and do it yourself if you so desired. Since I was essentially overriding with logging code, that's why nothing was happening (from a database perspective).

Resources