Using NSubstitute with a vb.net module - vb.net

We have some existing static methods that are grouped in VB modules.
I want to introduce unit testing to the company, and am looking into using NUnit and NSubstitute.
I can't seem to create a Substitute for the VB module I want to test, or find any examples of how to do this. I am trying to do something like:
Dim Sub = Substitute.For(MyModule)()
but VB tells me 'MyModule is a type and cannot be used as an expression'.
If I try
Dim Sub = Substitute.For(Of MyModule)()
VB tells me 'Module 'MyModule' cannot be used as a type'.
Have I got the syntax wrong or am I trying to do something stupid?

It is not appropriate to unit test Modules and Shared methods (static classes and methods in C#) with a mocking framework because:
Modules (static classes in C#) cannot:
inherit from base classes
implement interfaces
and thus, be mocked
Shared methods (static methods in C#) in mocked instances cannot be called
So, to unit test a Module or a class with Shared methods you need to do so directly. Example: (Unit test attributes omitted...)
Public Class A
Public Shared Function Go(a As Integer) As Integer
Return a + 10
End Function
End Class
Public Class TestClass
Public Sub Test()
Assert.AreEqual(A.Go(5), 15)
End Sub
End Class

make sure your sending in an interface and I wouldn't use a variable name as Sub as it's a reserved type.
Example
Dim fakeWebRequestService = Substitute.For(Of IWebRequestService)()

Related

Can't access methods in DLL

Using asp.net/vb.net. Created a solution with 2 projects, "MainProject" and "MyCommonStuff". The 2nd project ("MyCommonStuff") is really a common utilities class, the resulting dll I hope to use for other projects as well.
MyCommonStuff is defined very simply....
Public Class MyCommonStuff Stuff
Public Shared Function GetInfo() as string
:
:
End Function
Public Shared Sub Test
:
:
End Sub
:
End Class
In MainProject I set a reference to this MyCommonStuff project.
I want to access some of the MyCommonStuff methods in my code. But for some reason the methods are not being recognized.
For example, in a button in the MainProject I tried this....
dim m as new MyCommonStuff
x = m.GetInfo()
Intellisense doesn't pick up any of the subs/functions for m. What am I doing wrong? Thanks!
The thing is that you've made your methods static ("Shared" in VB). You need to either remove the Shared keywords:
Public Function GetInfo() As String
':
':
End Function
Public Sub Test()
':
':
End Sub
or keep the Shared keywords and use it like this:
x = MyCommonStuff.GetInfo()
Here is some information about Shared members. Most notably:
Specifies that one or more declared programming elements are
associated with a class or structure at large, and not with a specific
instance of the class or structure.
In other words, if you want to use your methods from an instance of your MyCommonStuff class, e.g. m in m.GetInfo(), you need to leave the Shared keyword off. If, on the other hand, you have a method that is common across all instances of your class or for which you don't even need an instance, you would use the Shared keyword and access the method like I said above, e.g. MyCommonStuff.GetInfo().
Make sure you're importing you common stuff's namespace.

Compiler doesn't see CompareTo method in IComparable(Of T) object

I'm trying to apply the answer to Implementing generic IComparer in VB to my project by implementing an IComparable interface for a class in VB.NET. The section for the GenericComparer in that answer compiles fine, but the IComparable interface on my specific object won't get past the compiler.
Public Class RowAndRanking
Implements IComparable(Of RowAndRanking)
Public html As String
Public rank As Double
Public Function CompareTo(other As RowAndRanking) As Integer
Return Math.Round(Me.rank - other.rank)
End Function
End Class
The compiler keeps insisting that "Class 'RowAndRanking' must implement 'Function CompareTo(other As RowAndRanking) As Integer' for interface 'System.IComparable(Of RowAndRanking)'.", but looking at my code, I can see that method signature. Furthermore, if I go to where I'm trying to run a Sort on a List of these objects, I can type:
Dim row as RowAndRanking = new RowAndRanking
row.CompareTo(...
And Visual Studio's code complete picks up the method signature.
I've tried cleaning and rebuilding the project, but the issue remains. I've tried changing it to use a non-generic comparer solution, but the compiler still doesn't see the CompareTo method. This should be simple, but the compiler just doesn't see the function. Has this happened to anyone else? Is there something else that I can try?
Unlike C#, VB requires that you explicitly mark implementing methods.
Add
Implements IComparable(Of RowAndRanking).CompareTo

Classes that don't have interfaces

I have read several questions on here and it appears that the general consensus is that an interface is not required for every class in a project. I have read posts like this: Is it the best practice to extract an interface for every class?.
I want to know how this applies to the .NET framework classes. I believe that all of the classes I have looked at either inherit from an abstract class e.g. SQLConnection inherits from dbConnection or implement and interface e.g. the Component class implements the IComponent interface.
I have a copy of Reflector, which I downloaded two months ago and I am awaiting the license (paid the fee recently). When I start to step through the code (using Reflector); am I going to see code like this:
Public Class Foo
Public Name As String
Public Property NameProperty()
Get
Return Name
End Get
Set(value)
Name = value
End Set
End Property
Public Shared Sub Main()
Dim f As Foo = New Foo
f.NameProperty = "Ian"
End Sub
End Class
rather than code like this:
Public Class Foo
Implements IFoo
Public Name As String
Public Property NameProperty() Implements IFoo.NameProperty
Get
Return Name
End Get
Set(value)
Name = value
End Set
End Property
Public Shared Sub Main()
Dim f As IFoo = New Foo
f.NameProperty = "Ian"
End Sub
End Class
Public Interface IFoo
Property NameProperty()
End Interface
Notice that there is an Interface used in the second code fragment. I am still struggling to understand when it is suitable not to use interfaces. Some developers say never. I suppose some of it is subjective.
As someone who strives to do things the right way, I struggle with this every time I start a new project. I've come to realize that it's mostly subjective; like saying "on which days is OK to not take a shower".
Of course it provides abstraction, improves testability, etc., but it can lead to unnecessary "class explosion". Adding interfaces to ancillary internal classes does more harm than good in my experience. I occasionally open a small project I did years ago and am shocked my the endless list of classes ... over-engineering!
As a rule, I use interfaces for APIs in class libraries. Other than that, I add them if time allows, or I have a special need to clarify how a section of code is supposed to be called by client code.

Visual Basic: Sub vs. Function and Module vs. Class

Here's a bit of an abstract question. Would it be appropriate to say that a Sub is to a Function what a Module is to a Class? The purpose of a function is to return something - a sub acts like a function but doesn't return anything. The purpose of a class is to be instantiated - a method acts like a class but can't be instantiated.
Is this a good analogy?
I would say no. It's more like a module is to a class what a Shared Sub/Function is to a normal instance Sub/Function.

How can I access variables in another class without deleting others?

I have been charged with porting a VB6 project into VB.NET. In vb6, if you were in a class separate to a particular variable, you could access that variable easily:
Public Class Foo
Public k As Integer
End Class
Public Class Bar
k = 12
End Class
In VB.NET, my understanding is that before you can use a variable in another class, you must declare a new instance of it:
Dim foobar As New Foo
This would be fine, but I have to access these variables from different classes and every time I declare a new instance, it wipes all old values from the variables, which I need. Can anybody help? I tried using Inherits statements but they presented many problems.
Thanks.
Nick
Your're looking for the shared keyword. This makes the member available to other classes without having to have an instance of your class. See MSDN for more info
For the port just use Public module like you would in vb6
Public Module Foo
Public k As Integer
End Module
Public Module Bar
Foo.k = 12
End Module
Its not good practice but it will help you do your first pass at the port. Ideally you would refactor out modules/shared functions as being able to access variable from any part in the system will produce code that is harder to maintain
Dim YourobjName As YourClassName = Me.DataContext
Now you can use public methods and functions with YourobjName. Here YourClassName will be the class you want to access the public objects.