Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue while calling Setup (mocked) method which is called from a method that is in Task Factory c# #927

Closed
RiteshKo opened this issue Sep 17, 2019 · 1 comment

Comments

@RiteshKo
Copy link

I have a common method which is being called multiple times(around 30-35 references in the project). This method is basically fetching data from DB into data table.

Following is the testable code:

public class MyApp
{
   private readonly IDataProvider _dbProvider;
   public MyApp(IDataProvider dbProvider)
   {
       _dbProvider = dbProvider;
   }

   public void Process()
   {
       string query = "something";
       Helper h = new Helper(_dbProvider);
       // This method will be called in the Process method several times
       var taskList = new List<Task>
       {
	   Task.Factory.StartNew(() =>
	   {
		 var data1 = h.GetData("abc");
	   }),
	   Task.Factory.StartNew(() =>
	   {
		 var data2 = h.GetData("def");
	   }),
	   Task.Factory.StartNew(() =>
	   { 
	        var data3 = h.GetData("xyz");
	   })
       };
      Task.WaitAll(taskList.ToArray());
    }
}

public interface IDataProvider 
{
   IDbConnection CreateConnection(string connectionString);
   DataTable FillDatatableFromAdapter(IDbCommand command);
}

public class DataProvider  : IDataProvider 
{
     public IDbConnection CreateConnection(string connectionString)
     {
         return new SqlConnection(connectionString);
     }

     public DataTable FillDatatableFromAdapter(IDbCommand command)
     {
          DataSet dataSet = new DataSet();
          SqlCommand sqlCommand = command as SqlCommand;
          using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
          {
              sqlDataAdapter.Fill(dataSet);
          }

          if (dataSet.Tables.Count == 0)
              return null;

          return dataSet.Tables[0];
     }
}

public class Helper
{
   private readonly IDataProvider _dbProvider;
   public Helper(IDataProvider dbProvider)
   {
       _dbProvider = dbProvider;
   }

   public DataTable GetData(string query)
   { 
       DataTable table = new DataTable();
       using (IDbConnection connection = 
       _databaseProvider.CreateConnection(_connectionString))
       {
           connection.Open();
           using (IDbCommand command = connection.CreateCommand())
           {
               command.CommandText = query;
               command.Connection = connection;
               table = _dbProvider.FillDatatableFromAdapter(command);
           }
       }
       return table;
    }   
}

I have mocked DB classes to not hit DB from unit tests. Following is the test case code:

[TestMethod]
public void TestMyApp()
{
     DataSet abcData= MockDataAdapter("abcJson");
     mockDatabaseProvider.Setup(x => x.FillDataSetFromAdapter(It.Is<IDbCommand>(c => c.CommandText.Equals("abc"))))
                                .Returns((IDbCommand command) =>
                                {
                                    return abcData;
                                });

      DataSet defData= MockDataAdapter("defJson");
      mockDatabaseProvider.Setup(x => x.FillDataSetFromAdapter(It.Is<IDbCommand>(c => c.CommandText.Equals("def"))))
                                .Returns((IDbCommand command) =>
                                {
                                    return defData;
                                });

       DataSet xyzData= MockDataAdapter();
       mockDatabaseProvider.Setup(x => x.FillDataSetFromAdapter(It.Is<IDbCommand>(c => c.CommandText.Equals("xyz"))))
                                .Returns((IDbCommand command) =>
                                {
                                    return xyzData;
                                });

      MyApp app = new MyApp(mockDatabaseProvider.Object);
      app.Process();
   //  And then after that I am testing some data.
}

 private DataSet MockDataAdapter(string json = null)
 {
       Mock<IDatabaseProvider> mockDb = new Mock<IDatabaseProvider>();
       Mock<IDbCommand> mockC = new Mock<IDbCommand>();
       Mock<IDbConnection> mockD = new Mock<IDbConnection>();

       mockC.SetupAllProperties();
       mockD.Setup(m => m.CreateCommand()).Returns(mockC.Object);
       mockDb.Setup(m => m.CreateConnection(It.IsAny<string>())).Returns(mockD.Object);

      DataSet dataSet = new DataSet();
      if (json != null)
      {
            DataTable table = new DataTable();
            table = (DataTable)JsonConvert.DeserializeObject(json, typeof(DataTable));
            dataSet.Tables.Add(table);
       }
       else
       {
            dataSet.Tables.Add();
       }
      return dataSet;        
}

I am mocking FillDataSetFromAdapter method and checking the value of CommandText to return what data. The mocked method is being called from GetData() method which is being called from the Task Factory and is calling three times to get 3 different types of data.

So the mocked method is called 3 times containing command text "abc","def","xyz". But every time Setup method is called for 3 types of queries it is calling only one Setup method which is resulting same data in data1,data2 and data3 in the Process method. I think for each call command text is only "abc" or "def" or "xyz" which results in calling only one Setup method.

And when I removed the Task factory dependency everything is working fine.

Any help??

@stakx
Copy link
Contributor

stakx commented Sep 17, 2019

Hi @RiteshKo. This issue tracker's focus is on the development and maintenance of Moq, and that's what we'd like to focus our limited resources on. Pure usage questions (such as yours) are a better fit for places such as Stack Overflow, where your question will also meet with a much larger audience. For these reasons I'm opting to close this issue.

@stakx stakx closed this as completed Sep 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants