InternalsVisibleTo usage

I do not know if you know  InternalsVisibleToAttribute

https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396  .

I have used on a project https://github.com/ignatandrei/WorldBankAPi , that deals with World Bank API to get information

Let’s take an example: Countries: http://api.worldbank.org/countries?format=json

I have had a class CountriesRepository, that deals with transforming countries Json from WorldBank to Country classes. How can I test it WITHOUT relying on reading data from the internet ?

Simple:

1. Make an interface to grab JSON , IJSonData

    public interface IJsonData
    {
        Task<string> JsonData(int page = 1);
    }

2. Make a class JSONCountry that reads JSON from HTTP and implements IJSonData

3.  Make the CountryRepository class with 2 constructors  – one with IJSonData and the default calling JSONCountry

[assembly: InternalsVisibleTo("WorldBank.Test")]
namespace WorldBank.Repository
{
    public class CountriesRepository
    {
        private IJsonData data;
        public CountriesRepository():this(new JsonCountries())
        {

        }
//this is internal - could not see by outside projects with exception of WorldBank.Test
//see InternalsVisibleTo above
        internal CountriesRepository(IJsonData data)
        {
            this.data = data;
        }
    }
}

Optional: when testing manually, save the json into same files on the hard disk – you will need for point 5

4. The code that will use CountryRepository in official way will use the default – will not see the one with IJSonData

var c = new CountriesRepository();
var data = c.GetCountries().Result;

5. The testing code will define another class JSONFromHard that implements IJSonData and reads data from Hard

class JsonFromHard : IJsonData
{
//code to read files from disk 
// you have saved those when testing manually 
//see point 2 the optional part 
}

6. Because I have defined InternalsVisibleToAttribute to the WorldBank.Test, the Test dll can see the constructor with IJSonData  and then it class with JSONFromHard   – and I have no dependecy on the Http

 

public void GetAndInterpretData()
        {
            //uses [assembly: InternalsVisibleTo("WorldBank.Test")]
            var c = new CountriesRepository(new JsonFromHard("Countries"));
            var data = c.GetCountries().Result;
            Assert.Equal(218, data.Length);
        }

You can download the project from https://github.com/ignatandrei/WorldBankAPi  to see working.