Unit testing philosophy

Background

Unit testing has been marketed as a silver bullet, but that obviously is not true. This article is to discuss what benefits one should expect and at which cost. I have written down some statements that have been said about unit testing in order to see to what extent they are true. The aim of unit testing is to lower the total cost of writing and maintaining code.

Expected benefits ??

  • Code is always tested. Both within modules (lets say service-classes) and between them. Opens up for a broad discussion on what “tested” means.
  • Safer to refactor code. This applies to smaller refactorings within a module, but also bigger ones where functionality moves from one module to another.
  • Faster feedback on what and where the error is. Unit tests are small and point out the exact problem.
  • We gain better understanding by working with the problem from two different angles – code and how it is being used. Therefore we get higher quality of code.

Overhead

The expected overhead in coding is about 30%. The cost is initial and is earned back in a later phase of testing and maintaining the code. True?

Assumptions

  • Tests are less likely to change than the code. This would support the case that the overhead cost is initial only.
  • Test are based on the client requirements. Therefore they are less likely to change. Refactoring the code does not affect tests.

Layers

The big question

  • A – Should a unit test only focus aspects that the specific service handles?
  • B – Or should it even include aspects of other services or persistence?

The answer to this question has whole bunch of consequences. If it is a yes/no questions. Unfortunately I have found no one actually talking about these aspects.

(A) If we are using repositories and unit-testing a service. Then we should not mock data-objects, but instead mock calls to the repositories.
(B) We use real repository classes but mock the underlying data objects.

Let’s say our service that we test has to block for non-authorized attempts.
(A) Mocks the underlying IAuthorizationService and fake that it return “no access”. We can verify that we called a method on IAuthorizationService. We would have to refactor the test if we switched to overload method in IAuthorizationService for some reason (eg refactoring IAuthorizationService).
(B) Mock the data-objects and call the real AuthorizationService. Requires knowledge of how permissions are stored. Should we mock IAuthorizationRepository and so on?

Problems

There is a high number of tests failing because of invalid mock data.
Fixing bad code – eg moving logic from a controller to a service – would require re-writing tests. Risk for “just mock that call”.
Attitude “just get the tests working” produces bad tests and false security. Belief that high code coverage means tested code.

.NET C# build RELEASE mode with full stack trace and line numbers

The default settings of .NET release builds excludes line numbers from the stack trace. Modify your project settings to see the line numbers even when built for Release.

Credits – this article is based on the information from:
http://stackoverflow.com/a/3137915 by Ben M
http://stackoverflow.com/a/628590 by Coxy
– and a comment from Gazeth
Google search

Modify project settings in Visual Studio (2013)

Select your project in Solution Explorer, then ALT+ENTER.
More information about optimized code (marked with blue) below.
Project settings

For web projects do even this

Uncheck “Exclude generated debug symbols”.
Web project settings

When publishing, use Release mode.
Web project publishing

Optimized code

.NET compilers use “inline” where useful. This is like instead of making a call to a small method, instead put the code in the calling method. That would give us a slightly different stack trace than without optimization (in debug mode).

Example of differences that may occur because of Optimize code. Method AssertTools.Assert is 2 lines of code.

public static void Assert(bool condition, string message)
{
    if (condition) return;
    throw new Exception(message);
}

Without optimization
release full debug - optimized

MSSQL SearchAllTables

Based on http://vyaskn.tripod.com/search_all_columns_in_all_tables.htm and http://stackoverflow.com/a/436676/412368.

Support for searching both text and numbers.
Optimized. Roughly 4-5 times faster.

IF OBJECT_ID ('dbo.SearchAllTables', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.SearchAllTables;
GO

CREATE PROC SearchAllTables 
(
	@SearchStr nvarchar(100)
)
AS
BEGIN

-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Customized and modified: 2014-01-21
-- Tested on: SQL Server 2008 R2

DECLARE @Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))

SET NOCOUNT ON

DECLARE @TableName nvarchar(256)
DECLARE @ColumnName nvarchar(128)
DECLARE @DataType nvarchar(128)

DECLARE @SearchStr2 nvarchar(110)
DECLARE @SearchDecimal decimal(38,19)
DECLARE @Query nvarchar(4000)
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%', '''')
SET @SearchDecimal = CASE WHEN ISNUMERIC(@SearchStr) = 1 THEN CONVERT(decimal(38,19), @SearchStr) ELSE NULL END
PRINT '@SearchStr2: ' + @SearchStr2
PRINT '@SearchDecimal: ' + CAST(@SearchDecimal AS nvarchar)

SET @TableName = ''
WHILE @TableName IS NOT NULL
BEGIN
    SET @ColumnName = ''
    SET @TableName = 
    (
        SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
        FROM    INFORMATION_SCHEMA.TABLES
        WHERE       TABLE_TYPE = 'BASE TABLE'
            AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
            AND OBJECTPROPERTY(
                    OBJECT_ID(
                        QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
                         ), 'IsMSShipped'
                           ) = 0
    )

    WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
    BEGIN
		SET @ColumnName =
		(
			SELECT MIN(QUOTENAME(COLUMN_NAME))
				    DATA_TYPE
			FROM    INFORMATION_SCHEMA.COLUMNS
			WHERE       TABLE_SCHEMA    = PARSENAME(@TableName, 2)
				AND TABLE_NAME  = PARSENAME(@TableName, 1)
				AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar',
								  'int', 'bigint', 'tinyint', 'numeric', 'decimal')
				AND QUOTENAME(COLUMN_NAME) > @ColumnName
		)
		SET @DataType =
		(
			SELECT DATA_TYPE
			FROM    INFORMATION_SCHEMA.COLUMNS
			WHERE       TABLE_SCHEMA    = PARSENAME(@TableName, 2)
				AND TABLE_NAME  = PARSENAME(@TableName, 1)
				AND QUOTENAME(COLUMN_NAME) = @ColumnName
		)
		PRINT @TableName + '.' + @ColumnName + ' (' + @DataType + ')'

        IF @ColumnName IS NOT NULL
        BEGIN
			IF @DataType IN ('int', 'bigint', 'tinyint', 'numeric', 'decimal')
			BEGIN
				IF @SearchDecimal IS NOT NULL
				BEGIN
					SET @Query = 'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(CAST(' + @ColumnName + ' AS nvarchar(110)), 3630) ' +
								 'FROM ' + @TableName + ' (NOLOCK) ' +
								 ' WHERE ' + @ColumnName + ' = ' + CAST(@SearchDecimal AS nvarchar)
					PRINT '    ' + @Query
					INSERT INTO @Results
					EXEC (@Query)
				END
			END
			ELSE
			BEGIN
				SET @Query = 'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) ' +
							 'FROM ' + @TableName + ' (NOLOCK) ' +
							 ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
				PRINT '    ' + @Query
				INSERT INTO @Results
				EXEC (@Query)
			END
        END
    END 
END

SELECT ColumnName, ColumnValue FROM @Results
END

Completely disable UAC in Windows

If you are tired of waiting for a dimmed screen and answering Yes in some unwanted dialogs, then you should disable UAC and enable “Always run as administrator”. Windows built-in inteface does not provide a way to do it. You have to execute the following registry change:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system]
"EnableLUA"=dword:00000000

Download and execute the registry change
Always run as administrato zipped reg-file

Best SQL group by – find, select and remove duplicate rows

Ever wanted to find duplicate data and select the actual rows?
Download complete example as sql-script

with MYCTE  as (
  SELECT DuplicateKey1
        ,DuplicateKey2 --optional
        ,count(*) X
  FROM MyTable
  group by DuplicateKey1, DuplicateKey2
  having count(*) > 1
) 
SELECT E.*
FROM MyTable E
JOIN MYCTE cte
ON E.DuplicateKey1=cte.DuplicateKey1
   AND E.DuplicateKey2=cte.DuplicateKey2
ORDER BY E.DuplicateKey1, E.DuplicateKey2, CreatedAt

If you want to keep only one of the rows. Choose if you keep the newest or oldest data.

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
 -- ORDER BY NEWID() -- if the duplicates are identical and you dont care which of the duplicates will be kept
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1

TFS ignore NuGet packages

Using Visual Studio 2013 (update 4) with TFS Azure (as a service).

Two steps are required:

1. NuGet client has a bug (more info here) and adds packages to TFS Pending changes list. Stop this by adding \.nuget\nuget.config under solution folder (see download below).

2. TFS client automatically detects changes in the file system. Use \.tfignore (in solution folder) file for stopping TFS client detecting changes under packages folder.

Download

Downlod zip-file including the files required – namely nuget.config and .tfignore. Unpack it into the solution folder.

Restart VS

Restart Visual Studio after unpacking the files.
It is likely that you have to UNDO the current Pending changes for packages folder (first time only).

Find Changeset By Comment for Visual Studio 2015 and 2013

Origin
Based on findchangeset.codeplex.com, but ported for Visual Studio 2015 and 2013. VS2015 port is done by Jason Croghan. See download links below.

Tested
Tested on Visual Studio 2015 Update 3, but should work regardless which update you have.
Tested on Visual Studio 2013 Update 3, but should work regardless which update you have.

Download for Visual Studio 2015
Zipped installer
Source code

Download for Visual Studio 2013
Zipped installer
Source code

HighChart datetime json

Examples from HighCharts show that they expect dates to be formatted as Date.UTC(2014, 0, 1). Date.UTC actually returns milliseconds since 1 jan 1970. So you can send it as a number from your backend.

In C# you would use the following method:

/// <returns>Milliseconds since 1 jan 1970</returns>
public static long UnixTimestamp(this DateTime date)
{
return (long)(date – new DateTime(1970, 1, 1)).TotalMilliseconds;
}

Google Zeitgeist 2013 slideshow autoplay

Use AutoHotKey and the script below.

xmin = 150
xmax = 500
ymin = 150
ymax = 1000

Loop
{
IfWinExist, Google Zeitgeist 2013
{
WinActivate ; Automatically uses the window found above.
WinWaitActive, , , 2

random, nmx, %xmin%, %xmax%
random, nmy, %ymin%, %ymax%
MouseClick, left, %nmx%, %nmy%
Sleep, 6000
MouseClick, left, %nmx%, %nmy%
}

Sleep, 1500
}