VBA Unit Testing - vba

I have been writing so OO VBA code, it really helps me to write frequent unit test.
My approach to writing these tests would involve writing a Sub names 'test_CLASSNAME' in there I woudl instantiate my object, set parameters, and concludee with Debug.Assert.
Problem is my classes are getting bit more complicated now and I would like to run unit tests that involve Private methods & properties of the class. Using my apprach that is ofcourse not possible because I am using an external Sub to call relevant methods.
So my question is what other approaches exist to Unit testing in VBA, preferablyu ones that manage to access private methods of a class?
I came across follwing post but solutions involved installing add-ons my work policy forbids from doing that. So I was specualting that if I could create a test subclass of the class I want to be tested I could access all internal stuff( This is for example how Ruby solves this using Module Test::Unit).
For Argument Sake here is a dummy Class that I want to test
Class Dummy
Private Priv1 as Integer
Private Class_Init()
Priv1 = 1
End Sub
Private Sub sub1()
Priv1 = 2
End Sub
End
And Here is How I would normally test this(Provided my method, and property was not private,thus in this case this is invalid):
Sub test_Dummy()
Dim tested as New Dummy
Debug.Assert tested.Priv1 = 1
tested.sub1
Debug.Assert tested.Priv1 = 2
Debug.Print "Dummy passed all tests"
End

The Rubberduck project started with the porting to C# of some VBA unit-testing code which you can find right here on Code Review Stack Exchange - it won't let you call Private methods, but if you can't install any IDE add-ins your best bet is probably to write your own.
I'm not going to detail everything here, but I encourage you to take a look at the Code Review post I just linked to (and the other related CR posts, too) and to implement your own version of it.
As for testing Private methods... don't do that. They're implementation details, at a lower abstraction level than what you're really testing. Test the Public methods that call them - if these methods work as they should, then the private methods are doing their job.

Related

Can I change a private methods visibility in order to unit test them

I see in this answer that for Java you can set the visibility of a private method to "true" in a unit test in order to test the method. Is there something like this available for VBA, so that I can unit test private methods using RD-VBA?
If not, and I have a class that works out some logic in three private methods and give it back to a return value, am I doomed to only give a input value and test the return value, without being able to test the three private methods doing the heave lifting in between?
You shouldn't need to write tests for private methods, regardless of the language. You test your public API, what's private is implementation detail that isn't relevant.
If it is relevant and important enough to be tested on its own, then you should extract that private method to another class, and expose it as a public member of that class.
For example once I had a form and I wanted to limit user input in a textbox to numeric characters, and since I'm reusing that logic elsewhere then instead of treating it as an implementation detail of my form, I extracted a AsciiInputValidator class, and its public IsValidNumericValue method could be tested in every possible way as its own SUT.
Don't test private methods: the public ones invoke them anyway.
Unfortunately the Extract Class refactoring feature is not implemented as of this writing, so for now Rubberduck can't do this automatically for you... but it's definitely in-scope and if you're reading this and you're up for a bit of a C# metaprogramming challenge, go for it, pull requests are always welcome!
Can you add a public wrapper like
public sub testPrivateSub(param1,param2...)
PrivateSub(param1,param2....)
end sub
private sub PrivateSub(param1,param2....)
....
end sub

Unit Testing concrete classes

I have inherited a project that has no interfaces or abstract classes i.e. concrete classes only and I want to introduce unit testing. The classes contain lots of functions, which contain business logic and data logic; breaking every rule of SOLID (http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29).
I had a thought. I was thinking about creating interfaces for each of the poorly designed classes, exposing all functions. Then at least I can Mock the classes.
I am relatively new to Unit Testing (I have experience with a project, which was very well developed using interfaces in the right places). Is it a good idea to do this i.e. create interfaces for all the concrete classes (exposing all the functions and sub routines), just for unit testing?
I have spent some time researching this but I have not found an answer.
If your project has no tests at all, before adding any unit tests I'd much rather create higher level tests (i.e acceptance, functional and/or integration tests).
When you have those tests in place you know that the system is behaving as it should and also that it has certain level of 'external' quality (meaning by this that the inputs and outputs of your program are the expected ones).
Once your high level tests are working, you could try to add unit tests to the classes that already exist.
I bet that you will find yourself in the need to refactor some of the existing classes if you want to be able to unit test them so you can use your high level tests as a safety net that will tell you if you've broken anything.
This is a tough thing to tackle. I think you are on the right track. You'll end up with some ugly code (such as creating header interfaces for each monolithic class), but that should just be an intermediate step.
I'd suggest investing in a copy of Working Effectively with Legacy Code. First you could start by reading this distillation.
In addition to Karl's options (which let you mock via interception), you could also use Microsoft Fakes & Stubs. But these tools will not encourage you to refactor the code to adhere to SOLID principles.
Yes, that is a good start, however, having interfaces is less of a priority than having dependencies injected. If all of your legacy classes gain interfaces, but hidden internally they are still all interdependent, the classes will still be no easier to test. For instance, let's say you had two classes that looked like this:
Public Class LegacyDataAccess
Public Function GetAllSales() As List(Of SaleDto)
' Do work with takes a long time to run against real DB
End Function
End Class
Public Class LegacyBusiness
Public Function GetTotalSales() As Integer
Dim dataAccess As New LegacyDataAccess()
Dim sales As List(Of SaleDto) = dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
I know what you're already saying... "I wish the legacy code was at least layered that well", but lets use that as an example of some legacy code which would be hard to test. The reason it's hard to test is because the code reaches out to the database and executes a time-consuming query on the database and then calculates the results from that. So, in order to test it in its current state, you would need to first write out a bunch of test data to the database, then run the code to see if it returns the correct results based on that inserted data. Having to write a test like that is problematic because:
It is a pain to write the code to setup the test
The test will be brittle because it depends on the outside database working properly and on it containing all the correct supporting data
The test will take too long to run
As you correctly observe, interfaces are very important to unit testing. So, as you recommend, lets add interfaces to see if it makes it any easier to test:
Public Interface ILegacyDataAccess
Function GetAllSales() As List(Of SaleDto)
End Interface
Public Interface ILegacyBusiness
Function GetTotalSales() As Integer
End Interface
Public Class LegacyDataAccess
Implements ILegacyDataAccess
Public Function GetAllSales() As List(Of SaleDto) _
Implements ILegacyDataAccess.GetAllSales
' Do work with takes a long time to run against real DB
End Function
End Class
Public Class LegacyBusiness
Implements ILegacyBusiness
Public Function GetTotalSales() As Integer _
Implements ILegacyBusiness.GetTotalSales
Dim dataAccess As New LegacyDataAccess()
Dim sales As List(Of SaleDto) = dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
So now we have the interfaces, but really, how does that make it any easier to test? Now we can easily create a mock data access object, which implements the same interface, but that's not really the core problem. The problem is, how do we get the business object to use that mock data access object instead of the real one? To do that, you need to take your refactoring to the next level by introducing dependency-injection. The real culprit is the New keyword in the following line of the business class:
Dim dataAccess As New LegacyDataAccess()
The business class clearly depends on the data access class, but currently it is hiding that fact. It's lying about it's dependencies. It's saying, come-on, it's easy, just call this method and I'll return the result--that's all it takes. When really, it takes a lot more than that. Now, let's say we stopped it from lying about it's dependencies and made it so it unabashedly stated them, like this:
Public Class LegacyBusiness
Implements ILegacyBusiness
Public Sub New(dataAccess As ILegacyDataAccess)
_dataAccess = dataAccess
End Sub
Private _dataAccess As ILegacyDataAccess
Public Function GetTotalSales() As Integer _
Implements ILegacyBusiness.GetTotalSales
Dim sales As List(Of SaleDto) = _dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
Now, as you can see, this class is much easier to test. Not only can we easily create a mock data access object, but now we can easily inject the mock data access object into the business object. Now we can create a mock which quickly and easily returns exactly the data we want it to return and then see if the business class returns the correct calculation--no database involved.
Unfortunately, while adding interfaces to existing classes is a breeze, refactoring them to use dependency-injection typically requires a lot more work. You will likely need to plan out which classes make the most sense to tackle first. You may need to create some intermediary old-school wrappers which work the way the code used to, so you don't break existing code while you are in the process of refactoring the code. It's not a quick and easy thing, but if you are patient and in it for the long-haul, it is possible to do it, and you will be glad you did.
I would recommend you go the interface route, but if you want to pay for a solution, then try one of these:
TypeMock
JustMock
Creating interfaces to test the classes is not a bad idea - the goal of unit testing is to exercise if the functions on a class are functioning as expected. Depending on the classes you are working with, this could be easier said than done - if there are a lot of dependencies on global states, etc. you will need to mock accordingly.
Given how valuable unit tests are, putting a bit of work into them (to a limit) will benefit you and developers you work with.
I prefer to create interfaces and classes as you need to test things and not all upfront.
Besides interfaces, you can use some techniques to test legacy code. The one I often use is "Extract And Override", where you extract some piece off "untestable" code inside other method and make it overridable. Them derive the class that you want to test and override the "untestable" method with some sensing code.
Using a mock framework will be as easy as adding keyword Overridable to the method and sets the returning using the mock framework.
You can find many techniques on the book "Working Effectively with Legacy Code".
One thing about existing code, is that sometimes it is better to write integration tests than unit tests. And after you have the behavior under test, you create unit tests.
Another tip is to start with modules/class that have less dependencies, that way, you become familiar with the code with less pain.
Let me know if you need an example about "extract and override" ;)

Sharing variable data between forms other than a Global Variable Class in Win Forms vb.net application

Currently in a Win Form application, im using a Global Variable Class which contains variables that are used to to share data. My question is, what other ways are there to achieve this? Best practises? and why?
Globals are bad for many reasons, but probably the most glaring reason is because, ideally speaking, every time you call the same method, passing it the same parameters, it should always do the same thing with the same results. Globals brake that rule. Suddenly your code starts behaving in unpredictable ways because something wasn't initialized properly somewhere else, or some global got modified incorrectly.
The best way I've found to get rid of the need for globals is to adhere to the principles of dependency injection (DI). There is much material on the topic online, but in a nutshell, rather than having classes reach out to create or find their dependencies on their own, they should simply request that the dependencies be provided to them, often in the constructor. Anything that you are accessing via global variables would, by definition, be considered dependencies of the classes that access them. Therefore, instead of, for instance, having a global settings object, like this:
Global settings As New Settings()
And then a class that uses it like this:
Public Class MyClass
Public Sub DoSomething()
If settings.SomethingEnabled Then
' ...
End If
End Sub
End Class
You would instead, do it like this:
Public Class MyClass
Public Sub New(settings As Settings)
_settings = settings
End Sub
Private _settings As Settings
Public Sub DoSomething()
If _settings.SomethingEnabled Then
' ...
End If
End Sub
End Class
This makes your code much cleaner, more flexible, and more reliable. It also makes the code far more testable too, which is a great added benefit.
Data should be shared according to how it is going to be used. If a variable is required across the entire application then it can be seen to have global scope and a global variable concept (e.g. public static shared) may well be appropriate.
Often this is not the case however as global variables should really be avoided (check out here and here for more reasoning)
Data should be encapsulated at the level it is required - for example if a form has data / variables within it that are applicable to it's function but where other forms need to now the value, this would be the ideal case for a public readonly property on the form, which would mask the actual detail of the variable from the rest of the aplication.

Declare global variables in Visual Studio 2010 and VB.NET

How do I declare a global variable in Visual Basic?
These variables need to be accessible from all the Visual Basic forms. I know how to declare a public variable for a specific form, but how do I do this for all the forms in my project?
There is no way to declare global variables as you're probably imagining them in VB.NET.
What you can do (as some of the other answers have suggested) is declare everything that you want to treat as a global variable as static variables instead within one particular class:
Public Class GlobalVariables
Public Shared UserName As String = "Tim Johnson"
Public Shared UserAge As Integer = 39
End Class
However, you'll need to fully-qualify all references to those variables anywhere you want to use them in your code. In this sense, they are not the type of global variables with which you may be familiar from other languages, because they are still associated with some particular class.
For example, if you want to display a message box in your form's code with the user's name, you'll have to do something like this:
Public Class Form1: Inherits Form
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
MessageBox.Show("Hello, " & GlobalVariables.UserName)
End Sub
End Class
You can't simply access the variable by typing UserName outside of the class in which it is defined—you must also specify the name of the class in which it is defined.
If the practice of fully-qualifying your variables horrifies or upsets you for whatever reason, you can always import the class that contains your global variable declarations (here, GlobalVariables) at the top of each code file (or even at the project level, in the project's Properties window). Then, you could simply reference the variables by their name.
Imports GlobalVariables
Note that this is exactly the same thing that the compiler is doing for you behind-the-scenes when you declare your global variables in a Module, rather than a Class. In VB.NET, which offers modules for backward-compatibility purposes with previous versions of VB, a Module is simply a sealed static class (or, in VB.NET terms, Shared NotInheritable Class). The IDE allows you to call members from modules without fully-qualifying or importing a reference to them. Even if you decide to go this route, it's worth understanding what is happening behind the scenes in an object-oriented language like VB.NET. I think that as a programmer, it's important to understand what's going on and what exactly your tools are doing for you, even if you decide to use them. And for what it's worth, I do not recommend this as a "best practice" because I feel that it tends towards obscurity and clean object-oriented code/design. It's much more likely that a C# programmer will understand your code if it's written as shown above than if you cram it into a module and let the compiler handle everything.
Note that like at least one other answer has alluded to, VB.NET is a fully object-oriented language. That means, among other things, that everything is an object. Even "global" variables have to be defined within an instance of a class because they are objects as well. Any time you feel the need to use global variables in an object-oriented language, that a sign you need to rethink your design. If you're just making the switch to object-oriented programming, it's more than worth your while to stop and learn some of the basic patterns before entrenching yourself any further into writing code.
Pretty much the same way that you always have, with "Modules" instead of classes and just use "Public" instead of the old "Global" keyword:
Public Module Module1
Public Foo As Integer
End Module
Okay. I finally found what actually works to answer the question that seems to be asked;
"When needing many modules and forms, how can I declare a variable to be public to all of them such that they each reference the same variable?"
Amazingly to me, I spent considerable time searching the web for that seemingly simple question, finding nothing but vagueness that left me still getting errors.
But thanks to Cody Gray's link to an example, I was able to discern a proper answer;
Situation;
You have multiple Modules and/or Forms and want to reference a particular variable from each or all.
"A" way that works;
On one module place the following code (wherein "DefineGlobals" is an arbitrarily chosen name);
Public Module DefineGlobals
Public Parts As Integer 'Assembled-particle count
Public FirstPrtAff As Long 'Addr into Link List
End Module
And then in each Module/Form in need of addressing that variable "Parts", place the following code (as an example of the "InitForm2" form);
Public Class InitForm2
Private Sub InitForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Parts = Parts + 3
End Sub
End Class
And perhaps another Form;
Public Class FormX
Sub CreateAff()
Parts = 1000
End Sub
End Class
That type of coding seems to have worked on my VB2008 Express and seems to be all needed at the moment (void of any unknown files being loaded in the background) even though I have found no end to the "Oh btw..." surprise details. And I'm certain a greater degree of standardization would be preferred, but the first task is simply to get something working at all, with or without standards.
Nothing beats exact and well worded, explicit examples.
Thanks again, Cody
Make it static (shared in VB).
Public Class Form1
Public Shared SomeValue As Integer = 5
End Class
Public variables are a code smell - try to redesign your application so these are not needed. Most of the reasoning here and here are as applicable to VB.NET.
The simplest way to have global variables in VB.NET is to create public static variables on a class (declare a variable as Public Shared).
A global variable could be accessible in all your forms in your project if you use the keyword public shared if it is in a class. It will also work if you use the keyword "public" if it is under a Module, but it is not the best practice for many reasons.
(... Yes, I somewhat repeating what "Cody Gray" and "RBarryYoung" said.)
One of the problems is when you have two threads that call the same global variable at the same time. You will have some surprises. You might have unexpected reactions if you don't know their limitations. Take a look at the post Global Variables in Visual Basic .NET and download the sample project!
small remark: I am using modules in webbased application (asp.net).
I need to remember that everything I store in the variables on the module are seen by everyone in the application, read website. Not only in my session.
If i try to add up a calculation in my session I need to make an array to filter the numbers for my session and for others.
Modules is a great way to work but need concentration on how to use it.
To help against mistakes: classes are send to the
CarbageCollector
when the page is finished. My modules stay alive (as long as the application is not ended or restarted) and I can reuse the data in it.
I use this to save data that sometimes is lost because of the sessionhandling by IIS.
IIS Form auth
and
IIS_session
are not in sync, and with my module I pull back data that went over de cliff.
All of above can be avoided by simply declaring a friend value for runtime on the starting form.
Public Class Form1
Friend sharevalue as string = "Boo"
Then access this variable from all forms simply using Form1.sharevalue
You could just add a new Variable under the properties of your project
Each time you want to get that variable you just have to use
My.Settings.(Name of variable)
That'll work for the entire Project in all forms
The various answers in this blog seem to be defined by SE's who promote strict adherence to the usual rules of object-oriented programming (use a Public Class with public shared (aka static), and fully-qualified class references, or SE's who promote using the backward-compatibility feature (Module) for which the compiler obviously needs to do the same thing to make it work.
As a SE with 30+ years of experience, I would propose the following guidelines:
If you are writing all new code (not attempting to convert a legacy app) that you avoid using these forms altogether except in the rare instance that you really DO need to have a static variable because they can cause terrible consequences (and really hard-to-find bugs). (Multithread and multiprocessing code requires semaphores around static variables...)
If you are modifying a small application that already has a few global variables, then formulate them so they are not obscured by Modules, that is, use the standard rules of object-oriented programming to re-create them as public static and access them by full qualification so others can figure out what is going on.
If you have a huge legacy application with dozens or hundreds of global variables, by all means, use Modules to define them. There is no reason to waste time when getting the application working, because you are probably already behind the 8-ball in time spent on Properties, etc.
The first guy with a public class makes a lot more sense. The original guy has multiple forms and if global variables are needed then the global class will be better. Think of someone coding behind him and needs to use a global variable in a class you have IntelliSense, it will also make coding a modification 6 months later a lot easier.
Also if I have a brain fart and use like in an example parts on a module level then want my global parts I can do something like
Dim Parts as Integer
parts = 3
GlobalVariables.parts += Parts '< Not recommended but it works
At least that's why I would go the class route.
You can pipe the variable in to a file in the output directory and then load that file in the variable.
Imports System.IO
This code writes the file.
Dim somevariable = "an example"
Dim fs As FileStream = File.Create("globalvars/myvar1.var")
Dim filedata As Byte() = New UTF8Encoding(True).GetBytes(somevariable)
fs.Write(filedata, 0, filedata.Length)
fs.Close()
This loads the file in another form.
Dim form2variable
Dim fileReader As String
fileReader = My.Computer.FileSystem.ReadAllText("globalvars/myvar1.var")
form2variable = filereader
Public Class Form1
Public Shared SomeValue As Integer = 5
End Class
The answer:
MessageBox.Show("this is the number"&GlobalVariables.SomeValue)

Basic questions about Classes, Modules and interaction

I am new to vb.net and very frustrated.
Like all good programmers I want to split my code into separate files based on functionality . Some of my code interacts with users via Forms and some interacts with lab equipment behind the scenes (no direct user interaction). Sometimes a user will change something that will impact the lab equipment and sometimes something will happen with the lab equipment that a user needs to be aware of. When I use VS to create files I have to choose a Module or Form. VS then creates an empty file with a with either
Public Class Foo
End Class
or
Module Foo
End Module
If I have a bunch of files, each a Module, and if I define routines in a Module to be Friend then I can call them from other Modules, so:
Module Foo
Friend Sub DoSomeWork()
End Sub
End Module
Code in Fee can call routines in Foo -
Module Fee
Friend Sub Stuff()
DoSomeWork()
End SUb
End Module
When I create a Form, VS creates a Class. I find that I can call subroutines defined in a Module from a Class but when I try to call from a Module into a Class I get an error that the routine I am trying to call is not declared. I also cannot call from one Class into another Class. Declarations seem to apply only to library routines outside my program.
I have looked through several online explanations and tutorials, but frankly I don't understand these nor do I care about "inheriting from the base class" and all the other gobbledygook that such "explanations" contain. I want to concentrate on building my application.
My Main form has the name "Main"
I tried putting all the module code into the Main Class first by renaming "Module Foo" to "Public Partial Class Main" - bad idea - creates an impossible-to-find duplicate error. I tried creating empty code files, defining them as Public Partial Class Main and putting the Module code into them, - this worked in that code in the Class Main could call the "Module" code (which was now in Main) and vice-versa, but, other Forms (of course I have more than one) are created by VS to have their own Classes and once the "Module" code is moved out of Modules into Class Main the other Forms(Classes) could not call the code anymore.
I just want some recipe (best practice) I can follow to for defining Modules and Classes so that code and data can be shared.
ANSWER from below
To invoke a subroutine in another Class you simply need to put the class name in front of the subroutine name.
So not
DoSomeWork()
but
Foo.DoSOmeWork()
This may be obvious to all of you experienced programmers but not to me. You do not have to prepend a class/module name to a Module-to-Module call or a Class-to-Module call, only to calls that are made into Classes. Personally, for the sake of consistency, I think the things should be the same, but it would probably violate some OO rule. Anyway thank you to all.
Generally, if you have a function that needs to be called from more than one form, or from forms and modules, put it in the main module. If you have an exceptional case and need to call a function or sub in a form from another form or a module, you can declare it to be public:
Public Class Form1
public sub test(i as integer)
...
end sub
end class
and then you can call it by referring to the class.subname:
call form1.test(7)
NomD,
Like all good programmers
you should indeed care
about "inheriting from the base class" and all the other gobbledygook that such "explanations"
This will make you a better programmer and taking the time to understand why proper code structuring is important will also begin to yield better results for you.
I am not sure why two commentors seem to have an issue with VB.Net. The question would be the same regardless of the language, since both are C# and VB are built on .Net. Code can be written poorly in C#, just like VB. Please leave the language wars at home. NormD, the answer to your question should really be to direct you to the resources needed to better understand the problem. Here is an article on scope that might help a bit - class scope. The reason you are getting the behavior that you see is due to what you are working with. Modules (similar to static classes in C#) are created when you program begins, so there is no need to create them. So you can reference a method on a module, like so - module.method. Classes on the other hand, some exceptions, need to be created in order to be referenced. So to use an employee (or form class) you must create a variable of that class. So you would use dim myemp as New Employee() and then call myemp.method() from your module. This is a rather simplistic description, so please read the scope article and other MSDN articles for more information. I am sure other posters can post additional links with good information. Hope this helps a bit.
Wade
It seems like you don't understand the basics of object-oriented programming (OOP).
If you DON'T want to learn how to design your application in an object-oriented way, then only create modules in your application and you will be able to call functions from one to another without any problem. But this will result in code that will not be easily maintainable and scalable.
The other option is to learn OOP by picking a book about it, or following a course or tutorial on the subject. It's a significant investment but it will result in more robust code that will scale better when your application grows.