[Event] SOLID with C#

Another event is coming. This time I will be talking about SOLID principles with C#.

I will be covering each one of them while we write a functional project using C# as language base.

If you want to join me, here is the registration link: https://mug-it.org.ar/event.aspx?event=521

A not so funny joke – Bad requirements

These days an image that is meant to by funny about our profession has been shared around different social networks.

This joke shows something that is expected from testers: Having a feature, try to think beyond the obvious behaviour and always look for ways to push the limit of what was implemented.

This makes perfect sense because developers tends to focus on the problem resolution but, due different constraints (Time, technology or knowledge) there are many cases that escapes to theirs intellect.

Although, this image pictures a different reality that is quite usual to find on projects: Inaccurate requirement descriptions.

If you use Scrum, you can call it “user stories“, if you use another, more traditional, model you could call them “use cases“. Anyhow, the problem of that picture is not the tester finding what could looks like the edge cases. The problem with the picture is what the tester is describing (And testing) are requirements that were never asked or were never shown to the developer.

This, let call it, anti management pattern happens so frequently that is accepted and added into the development process by all the stakeholder. From developers to mangers, even customers. All of them have naturalized this problem.

One of the most common reasons behind this behaviour is justified with fancy words such as: we are agile; the customer is not paying for this time; we can put this under the carpet (Or, technical debt if you don’t like to feel old)

In the other hand we must consider one of the golden rules of any developer: Do not code what is not need it.

This means that you should stop coding in the precise moment in which you, as a developer, start feeling that little voice in your head that says: C’mon, add that feature just in case…

So, again, what the developer did is almost perfect (It could have another type of bugs). Which is far from perfection. Far from be even an approximation of correctness if the requirements are discovered during the testing face. And there is a way to spot the problem, the way to know if we are suffering this anti management pattern: Count how many user stories are bouncing from developers to testers, and viceversa, that, for each bounce, the requirements gain in written lines.

Summarizing the idea behind this post I would say that picture IS a funny joke, but only if we forget those common problems that mine our projects: Poor requirement descriptions on the sake of feeling more agile; coded features making round trips from developers to testers and back, just because no one took the time of be sure that the requirement were correctly written down.

Mock objects for unit testing with Lua

From the last post, I have explained the first basic steps to start unit testing Lua code. Clearly, those tests were very basics and, usually, will not represent the most common case scenarios of real, production level, code.

In any development (Unless that we decided to use a different coding paradigm) having objects that encapsulate functionality is the common pattern.

Those objects will contains functionality in form of functions, methods and other structures. It will handles data, expect data and produce data. And, of course, we need to test these interactions and results.

Testing injecting dependencies

We will start with something simple: Functions that depends on objects.

This is clearly a very common scenario. You have a function that requires the services of an object. At some point we will test the object but, to keep it simple, we need to test the function that consumes the services of this object and produce a particular result.

function IsUserMinor()
    local age = IdentityService:GetUserAge()
    return age <= 18
end

In Lua we can have global and local variables. The previous example could look odd if you come from pure OOP languages. It is clear this function is coupled but, and here is where the Lua magic enters in play, that IdentityService object could be, in fact, anything. For sure we could have passed this as a parameter but, again, due the nature of Lua, this function is grabbing the object from the context, which can be anything (Saying that, I will bring a better version in following posts).

So, we have this function in one single file. The function checks if the user is a minor or not and returns a boolean. Very simple but: how is it this running? You may ask (I hope so).

require('objects/identity')
require('validators/isNotMinor')

local isMinor = IsUserMinor()

if isMinor then
    print('User is minor')
else
    print('User is not minor')
end

As can be seen in this file. It is this file the one that creates the context. Putting together the file with our function, the file with the Identity Service object and some small code. Considering this is possible to do, we just need to replicate these conditions in our tests.

Creating a mock object

A mock object is a representation of the object that we want to substitute but with custom functionality that we can control. The original object, IdentityService, could be trying to connect to a data base or a directory system requiring more services and configurations that we do not want to orchestrate for a test, and in particular, for unit testing our function. Just think on all the possible prerequisites, including a testing server with fake data only to avoid touch real data. Also, real data can be modified by external agents which will cause our tests to fail: We need to have control over our tests.

mockObject = { }
mockObject.__index = mockObject

function mockObject:new()
    local obj = { }
    setmetatable(obj, mockObject)
    obj.attributes = { }
    return obj
end

function mockObject:GetAttribute(name)
    return self.attributes[name]
end

function mockObject:SetAttribute(name, value)
    self.attributes[name] = value
end

In Lua, this can be consider a standard object in which we have added two properties: GetAttribute and SetAttribute. We will use these properties to allow the test the creation of properties and values that could be required by the different scenarios.

Injecting the mock and testing

As I said at the beginning. We need to replicate a similar execution environment allowing us to use the mock instead of the real object.

local luaUnit = require('../unittest/luaunit')
require('../unittest/mocks')
require('../validators/isNotMinor')

function mockObject:GetUserAge()
    return self.attributes['age']
end

IdentityService = mockObject:new()

Because we can add functions into our objects. Adding the GetUserAge function is need it. This function will retrieve a particular attribute “age” which will be injected during the test preparation phase.

function DoTest(age, expected)
    IdentityService:SetAttribute('age', age)
    local result = IsUserMinor()
    luaUnit.assertEquals(result, expected)
end

As in the previous post, the DoTest function acts as a helper and encapsulates the code to be reusable. In it, the expected age is set before calling the function that is being tested. Remember, the object IdentityService is global and was previously declared in this execution context. This will ensure that IsUserMinor function is still able to find this object and use it.

Finally, we need to declare our test.

DoTest(10, true)

It is important to clarify this approach is not totally correct. As I mentioned some lines above, the function itself is coupled and more work can be done but, from testing perspective, the injection of the object is still pretty good.

First steps testing Lua code

Lua might be one of those languages which few have heard about it. Usually there are no job offers from companies looking for Lua developers as for C#, Java or any new fashion JavaScript framework.

But, there are a reality and is that Lua is there, behind many big systems, videogame engines and servers.

It is quite common to use Lua for add functionality to these systems. Perhaps one of the most known systems that uses Lua is Roblox. That videogame application that gather thousand of players and, in which, you can create your own 3D games and make some money on the process. But, as I said, as with Roblox, there are many other places in which Lua is required and having some knowledge around this language could be something to consider for any developer toolbox.

So, I will assume that you already have some basic knowledge of Lua, but if you don’t, no worries, I will use very simple example which any developer could understand. And, of course, the important part here is testing over Lua as a language.

Creating code to test

Clearly, something that we need is some functional code to test. For the sake of this post (Keep it simple) we will write a couple of basic functions:

function sum(a, b)
    return a + b
end

function substract(a, b)
    return a - b
end

Now we have some code and the question that requires an answer is: How we test this?

The testing framework

It is clear that for unit test any piece of code you don’t need a framework. A framework could give you some benefits but not having one is not a blocker. You can still test without a testing framework. In any case, we will use one 🙂

We will use Lua Unit, which has a wide set of functions to help us during the testing process. So, lets create another file in which we will write our unit tests.

--import Lua Unit
local luaUnit = require('./luaunit')

--import math functions file
require('./math')

Lua Unit can be fully downloaded in one single file and included into our testing file using require command. In the same way, we can import the functions to test from the file in which we wrote them.

Unit testing our code

Having imported the files and the framework, the next step will be to write the testing code. One good practice for unit testing, as in any other language, is to encapsulate any data initialization and repeated code in such way that we can reuse it, helping the functional test to focus on that action: testing.

function DoTest(valA, valB, expected)
    local result = sum(valA, valB)
    luaUnit.assertEquals(result, expected)
end

In the previous code, the function DoTest parameterize the test process allowing any other test to consume its services and act in consequence.

function When_Sum10and10_Expect_20()
    DoTest(10, 10, 20)
end

The testing function follows one of the many naming conventions (Which can be changed at will) and encapsulate what need to be tested. Depending of how we are use to do testing, we could expect to have the assert call inside of the test and not in the helper function.

Finally, we need to perform a call to this function and execute the test.

When_Sum10and10_Expect_20()

If all goes good and the tests pass, Lua Unit will do its work and no messages will be shown. In the other hand, we can let Lua Unit to show more detailed information about the execution adding the following at the end of our script.

os.exit( luaUnit.LuaUnit.run() )

But even without the previous line we will be getting error messages if any unit test fails, having an instant feedback of our code.

[Podcast] Impostor syndrome

This weekend I participated in another podcast. This time with Bruno Capuano and Juan Quijano. Actually, is their podcast and I was the guest 🙂

For this one we talked about a different topic but related to technology and individuals: The impostor syndrome.

Also, the chat move us to include a little but of the well-known Dunning-Kruger effect and some “war stories” from our career.

If you want to listen the podcast, follow the link (Spanish, of course).

[Event] Global AI Tour Argentina

Yes, another event is coming and I am giving a lecture around a very interesting topic: Machine Learning, Artificial Intelligence and how the most commonly used learning models uses some basic concepts to build more complex algorithms.

There will be many more lectures on the event and, because is a virtual event due the current quarantine state, the event will be done in different days, so, there is no reason to miss it 🙂

Check here to register on my track: https://globalaitour.conosur.tech/cordoba-sabado-23-de-mayo/