I recently received some feedback about some tests we wrote a long time ago from a contractor for a legacy application. I am confused with the terminology that he used and I won't get chance to talk to him again for another month (when I will speak to him). Please see the code below:
[TestMethod]
public void Is_Correct_Months()
{
IService service = new Service();
DataTable t1 = service.GetMonths();
DataTable t2 = BuildExpectedTable();
Assert.IsNotNull(t1);
Assert.AreEqual(t1.Rows.Count, t2.Rows.Count);
for (int i = 0; i <= 2; i++)
{
Assert.AreEqual(t1.Rows[i][0], t2.Rows[i][0]);
Assert.AreEqual(t1.Rows[i][1], t2.Rows[i][1]);
}
}
public DataTable BuildExpectedTable()
{
DataTable dt = new DataTable();
//Add column names to datatable
dt.Columns.Add("Column1", typeof(string));
dt.Rows.Add("January");
dt.Rows.Add("May");
dt.Rows.Add("December");
return dt;
}
Question: Is the BuildExpectedTable method a Stub or not in this case? Is it a bad idea to Assert against BuildExpectedTable (as I have done)?
Now see the code below:
var mockCalculator = new Moq.Mock<ICalculator>();
mockChangeCalculator.SetupProperty(client => client.Number1, 400).SetupProperty(client => client.Number2, 200);
This is obviously a mock. Question: Could it ever be construed as a Stub?
Now see the code below:
int[] values = new int[] { 1, 3, 5, 9 };
IEnumerable<int> processed = ProcessInput(values);
int[] expected = new int[] { 1, 9, 25, 81 };
CollectionAssert.AreEqual(expected, processed);
Question: Is expected a stub in this case?
Update
[TestMethod]
public void Is_Correct_Months()
{
IService service = new Service();
DataTable t1 = service.GetMonths();
DataTable dt2 = new DataTable();
//Add column names to datatable
dt.Columns.Add("Column1", typeof(string));
dt.Rows.Add("January");
dt.Rows.Add("May");
dt.Rows.Add("December");
Assert.IsNotNull(t1);
Assert.AreEqual(t1.Rows.Count, t2.Rows.Count);
for (int i = 0; i <= 2; i++)
{
Assert.AreEqual(t1.Rows[i][0], t2.Rows[i][0]);
Assert.AreEqual(t1.Rows[i][1], t2.Rows[i][1]);
}
}
Related
I have a datatable with 1000 records. Each row has a column with a link.I will loop the datatable and fetch record from the website using the link in the datatable. The code is working fine , but this is taking too much time to retrieve the records. So I need to pass it in multiple threads and fetch records and add all the records to a single datatable. I an using C# , Visual studio 2015.
How can we do using threading C#, Any help appreciated.
Existing code is as below.
for (int i = 0; i < dt.Rows.Count; i++)
{
String years = String.Empty;
dt.Rows[i]["Details"] = GetWebText(dt.Rows[i]["link"].ToString());
}
private String GetWebText(String url)
{
var html = new HtmlAgilityPack.HtmlDocument();
string text= html.LoadHtml(new WebClient().DownloadString(url));
return text;
}
You are going to run in to issues here with the thread-safety of write operations with data tables. So you need to ensure that the operations that you perform are separated nice.
The good thing is that you are actually doing three distinct steps and you can easily break them apart and parallelize the slow part while keeping it thread-safe.
Here's what your code is doing:
var url = dt.Rows[i]["link"].ToString();
var webText = GetWebText(url);
dt.Rows[i]["Details"] = webText;
Let's process the data in these three steps, but only parallize the GetWebText part.
This is how:
var data =
dt
.AsEnumerable()
.Select(r => new { Row = r, Url = r["link"].ToString() })
.AsParallel()
// This `Select` is the only part run in parallel
.Select(x => new { x.Row, WebText = GetWebText(x.Url) })
.ToArray();
foreach (var datum in data)
{
datum.Row["Details"] = datum.WebText;
}
Blocking Collections can solve the problem:
Blocking<string> links= new BlockingCollection<string>();\\ using System.Collections.Concurrent;
Blocking<string> results= new BlockingCollection<string>();
public static void main()
{
//get your datatable
for (int i = 0; i < dt.Rows.Count; i++)
{
ThreadStart t = new ThreadStart(threads);
Thread th = new Thread(t);
th.Start();
}
for (int i = 0; i < dt.Rows.Count; i++)
{
links.add(dt.Rows[i]["link"].ToString());
}
for (int i = 0; i < dt.Rows.Count; i++)
{
dt.Rows[i]["Details"] = results.Take();
}
}
public void threads()
{
while(true)
{
string url= Links.take();//block if links is empty
var html = new HtmlAgilityPack.HtmlDocument();
string text= html.LoadHtml(new WebClient().DownloadString(url));
results.add(text);//add result to the other queue
}
}
This question already has answers here:
List.Add seems to be duplicating entries. What's wrong?
(6 answers)
Closed 7 years ago.
I have a method that returns the List of data for Kendo scheduler. My problem is, There are 39 unique records I can get from the DB.
Here also I got the 39 records but all records are the last indexed record data:
protected object GetData()
{
cal_details cal = new cal_details();
List<cal_details> lst = new List<cal_details>();
DataSet dSet = new DataSet();
try
{
dSet = (DataSet) DAL.SC(1, 1, 0, 0, 0, "", "", "", 1, "tblCal");
if (dSet.Tables["tblCal"].Rows.Count > 0)
{
lst.Clear();
for (int i = 0; i <= dSet.Tables["tblCal"].Rows.Count - 1; i++)
{
cal.Description = "Test";
cal.isAllDay = true;
//cal.OwnerID = 2;
cal.Start = Convert.ToDateTime(dSet.Tables["tblCal"].Rows[i]["working_date"].ToString());
cal.End = Convert.ToDateTime(dSet.Tables["tblCal"].Rows[i]["working_date"].ToString());
cal.OwnerID = dSet.Tables["tblCal"].Rows[i]["date_cat"].ToString();
cal.TaskID =i;
cal.Title = "Test Title";
lst.Add(cal);
}
}
return lst;
}
catch (Exception ex)
{
throw new HttpResponseException(new HttpResponseMessage() { StatusCode = HttpStatusCode.NoContent, Content = new StringContent("There were some Errors") });`enter code here`
}
}
You are using the same cal_details object. You need to create a new object for each row.
Move this line:
cal_details cal = new cal_details();
inside the for loop like this:
for (int i = 0; i <= dSet.Tables["tblCal"].Rows.Count - 1; i++)
{
cal_details cal = new cal_details();
//...
}
You're basically creating one object which you change several times in the loop and then add it several times to a list. It results in a list where all the elements is the same piece of data.
Solution:
Move
cal_details cal = new cal_details();
into the loop
for (int i = 0; i <= dSet.Tables["tblCal"].Rows.Count - 1; i++)
{
cal_details cal = new cal_details();
...
I add rows to the table configs like this, any form that i want
DataRow row2 = DataAccess.Instance.configs.NewRow();
row2["Nome"] = "abrirficheiro";
row2["Valor"] = Convert.ToString(Variables.abrirficheiro);
DataAccess.Instance.configs.Rows.Add(row2);
but i wanna keep the row at index 0 (the first one) untouched, any idea how it's done?
edit: i've been working around it for the past hour, still unsucessful
The table class code is like this
public sealed class DataAccess
{
static readonly DataAccess instance = new DataAccess();
//**adicionar tabelas aqui
public DataTable configs { get; private set; }
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static DataAccess()
{
}
DataAccess()
{
this.configs = new DataTable("configs");
TabelasSET.Tables.Add("configs");
configs.Columns.Add("Nome");
configs.Columns.Add("Valor");
}
public static DataAccess Instance
{
get
{
return instance;
}
}
}
Solved: Modified the code this way
DataRow row2 = DataAccess.Instance.configs.NewRow();
row2["Nome"] = "abrirficheiro";
row2["Valor"] = Convert.ToString(Variables.abrirficheiro);
DataAccess.Instance.configs.Rows.InsertAt(row2, 2);
DataAccess.Instance.configs.Rows.RemoveAt(1);
//second set
DataRow row3 = DataAccess.Instance.configs.NewRow();
row3["Nome"] = "mantergravacao";
row3["Valor"] = Convert.ToString(Variables.mantergravacao);
DataAccess.Instance.configs.Rows.InsertAt(row3, 3);
DataAccess.Instance.configs.Rows.RemoveAt(2);
And so on, basicaly, you gotta insert it first, then remove, i'm sure there are other ways but this has been working flawlessly
DataAccess.Instance.configs.Rows.InsertAt(row2,1)
try this one
DataRow row2 = DataAccess.Instance.configs.NewRow();
row2["Nome"] = "abc";
row2["Valor"] = "123";
DataAccess.Instance.configs.Rows.InsertAt(row2, 1);
DataRow row2 = DataAccess.Instance.configs.NewRow();
row2["Nome"] = "zyx";
row2["Valor"] = "789";
DataAccess.Instance.configs.Rows.InsertAt(row2, 2);
Trying to calculate a column value with linq. It sums correctly but produces incorrect value when dividing or multiplying. Example is below.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DataTable dtWidgets = Get_widgets();
DataTable dtHits = Get_hits();
var hit_rate =
from w in dtWidgets.AsEnumerable()
join h in dtHits.AsEnumerable()
on w[0] equals h[0]
select new
{
Date = w.Field<DateTime>("calendar_date"),
Widgets = w.Field<int>("widgets"),
Hits = h.Field<int>("hits"),
TestSum = w.Field<int>("widgets")+h.Field<int>("hits"),
TestMult = w.Field<int>("widgets") * h.Field<int>("hits")
};
gvWidgets.DataSource = dtWidgets;
gvWidgets.DataBind();
gvHits.DataSource = dtHits;
gvHits.DataBind();
gvLinq.DataSource = hit_rate.ToArray();
gvLinq.DataBind();
}
static DataTable Get_widgets()
{
DataTable widgets = new DataTable();
widgets.Columns.Add("calendar_date", typeof(DateTime));
widgets.Columns.Add("widgets", typeof(int));
widgets.Rows.Add("05/15/2012", 200000);
widgets.Rows.Add("05/16/2012", 210000);
return widgets;
}
static DataTable Get_hits()
{
DataTable hits = new DataTable();
hits.Columns.Add("calendar_date", typeof(DateTime));
hits.Columns.Add("hits", typeof(int));
hits.Rows.Add("05/15/2012", 100000000);
hits.Rows.Add("05/16/2012", 120000000);
return hits;
}
}
Returns:
Date Widgets Hits TestSum TestMult
5/15/2012 12:00:00 AM 200000 100000000 100200000 -1662697472
5/16/2012 12:00:00 AM 210000 120000000 120210000 1426874368
Given the example numbers you have listed underneath the code, it looks like you're getting integer overflow. Try making the field type Int64.
If I where you, I would look at the limit of int in c#... (2147483647)
Try with long (= Int64)
20000000000000
>
2147483647
New to LINQ and c# but having problem with one specific problem.
I have 2 Data tables.
DataTable 1 has Name, House Number in it. DataTable 2 holds Street, FirstHouseNumber, LastHouseNumber.
What I want to do is create a new table that has Name, House Number, Street in it but I keep ending up with lots of DataTable1 Count * DataTable2 Count when I would only expect the same count as DataTable 1.
Heres the expression I am using:
var funcquery = from name in DT1.AsEnumerable()
from street in DT2.AsEnumerable()
where name.Field<int>("Number") >= street.Field<int>("FirstHouseNumber") && name.Field<int>("Number") <= street.Field<int>("LastHouseNumber")
select new { Name = name.Field<string>("Name"), Number = name.Field<int>("Number"), street.Field<string>("Street") };
What am I doing wrong? I just cant get it at all.
TIA.
This will be easier to think about with a more specific example:
Name House Number
------ ------------
Chris 123
Ben 456
Joe 789
Street First House Last House
Number Number
-------- ------------ ------------
Broadway 100 500
Main 501 1000
To demonstrate the results using this data, I use the following code:
class HouseInfo
{
public string Name;
public int HouseNumber;
public HouseInfo(string Name, int HouseNumber)
{
this.Name = Name;
this.HouseNumber = HouseNumber;
}
}
class StreetInfo
{
public string Street;
public int FirstHouseNumber;
public int LastHouseNumber;
public StreetInfo(string Street, int FirstHouseNumber, int LastHouseNumber)
{
this.Street = Street;
this.FirstHouseNumber = FirstHouseNumber;
this.LastHouseNumber = LastHouseNumber;
}
}
static void Main(string[] args)
{
HouseInfo[] houses = new HouseInfo[] {
new HouseInfo("Chris", 123),
new HouseInfo("Ben", 456),
new HouseInfo("Joe", 789) };
StreetInfo[] streets = new StreetInfo[] {
new StreetInfo("Broadway", 100, 500),
new StreetInfo("Main", 501, 1000)};
var funcquery = from name in houses
from street in streets
where name.HouseNumber >= street.FirstHouseNumber && name.HouseNumber <= street.LastHouseNumber
select new { Name = name.Name, Number = name.HouseNumber, Street = street.Street };
var results = funcquery.ToArray();
for (int i = 0; i < results.Length; i++)
{
Console.WriteLine("{0} {1} {2}", results[i].Name, results[i].Number, results[i].Street);
}
}
The results are:
Chris 123 Broadway
Ben 456 Broadway
Joe 789 Main
This seems to be what you are after, so I don't think the problem is in the code you've given. Perhaps it is in the data itself (if multiple streets include the same house range) or something else. You may need to supply more specific data that demonstrates your problem.
Here's the same code implemented using DataTables instead of classes. It yields the same result:
System.Data.DataTable DT1 = new System.Data.DataTable("Houses");
System.Data.DataTable DT2 = new System.Data.DataTable("Streets");
DT1.Columns.Add("Name", typeof(string));
DT1.Columns.Add("Number", typeof(int));
DT2.Columns.Add("Street", typeof(string));
DT2.Columns.Add("FirstHouseNumber", typeof(int));
DT2.Columns.Add("LastHouseNumber", typeof(int));
DT1.Rows.Add("Chris", 123);
DT1.Rows.Add("Ben", 456);
DT1.Rows.Add("Joe", 789);
DT2.Rows.Add("Broadway", 100, 500);
DT2.Rows.Add("Main", 501, 1000);
var funcquery = from System.Data.DataRow name in DT1.Rows
from System.Data.DataRow street in DT2.Rows
where (int)name["Number"] >= (int)street["FirstHouseNumber"]
&& (int)name["Number"] <= (int)street["LastHouseNumber"]
select new { Name = name["Name"], Number = name["Number"], Street = street["Street"] };
var results = funcquery.ToArray();
for (int i = 0; i < results.Length; i++)
{
Console.WriteLine("{0} {1} {2}", results[i].Name, results[i].Number, results[i].Street);
}