Ok, I've got a strange problem. I am testing a usercontrol and have code like this:
[TestFixture]
public myTestClass : UserControl
{
MyControl m_Control;
[Test]
public void TestMyControl()
{
m_Control = new MyControl();
this.Controls.Add(m_Control);
Assert.That(/*SomethingOrOther*/)
}
}
This works fine, but when I change it to:
[TestFixture]
public myTestClass : UserControl
{
MyControl m_Control;
[Setup]
public void Setup()
{
m_Control = new MyControl();
this.Controls.Add(m_Control);
}
[TearDown]
public void TearDown()
{
this.Controls.Clear();
}
[Test]
public void TestMyControl()
{
Assert.That(/*SomethingOrOther*/);
}
}
I get an Object Reference Not Set To An Instance of an Object. I even output to the console to ensure that the setup/teardown were running at the correct times, and they were... but still it isn't newing up the usercontrols.
edit> The exact code is:
[TestFixture]
public class MoneyBoxTests : UserControl
{
private MoneyBox m_MoneyBox;
private TextBox m_TextBox;
#region "Setup/TearDown"
[SetUp]
public void Setup()
{
MoneyBox m_MoneyBox = new MoneyBox();
TextBox m_TextBox = new TextBox();
this.Controls.Add(m_MoneyBox);
this.Controls.Add(m_TextBox);
}
[TearDown]
public void TearDown()
{
this.Controls.Clear();
}
#endregion
[Test]
public void AmountConvertsToDollarsOnLeave()
{
m_MoneyBox.Focus();
m_MoneyBox.Text = "100";
m_TextBox.Focus();
Assert.That(m_MoneyBox.Text, Is.EqualTo("$100.00"), "Text isn't $100.00");
}
[Test]
public void AmountStaysANumberAfterConvertToDollars()
{
m_MoneyBox.Focus();
m_MoneyBox.Text = "100";
m_TextBox.Focus();
Assert.That(m_MoneyBox.Amount, Is.EqualTo(100), "Amount isn't 100");
}
}
I get the exception(s) at the respective m_MoneyBox.Focus() calls.
Solved - See Joseph's comments
I created a test case with exactly the same layout you presented here, but with a TextBox instead of a MyControl. I also added a constructor and a deconstructor and outputted all the various stages to the console to see the sequence of events. However, I never got an object reference exception.
In case you are interested, the sequence was [constructor called], [setup called], [test called], [tear down called]. The deconstruction never output anything to the screen for some reason.
My original thought was that the Controls property on myTestClass would not be initialized, but on my test it was, so I think it has something to do with your MyControl construction.
edit> I added the focus on my TextBox in my unit test as well but still no exception. Does your MoneyBox have any event handling going on behind the scenes during the Focus? That might be your culprit.
You haven't said where you're getting the exception, which would help - what does the stack trace look like?
It's very odd (IME) to derive from UserControl when you create a test fixture. Aside from anything else, I don't know that NUnit is going to call Dispose for you at any appropriate point... what's the purpose of it here? Can you not make your tests run with a "plain" test fixture?
I had exactly the same issue, so my apologies for answer to this old post.
The problem in your code (and mine) is that you are creating 2 different instances for MoneyBox and 2 more for TextBox. So, the initial assignation inside Setup, is valid only for Setup method and out_of_scope in the test methods.
Inside the Setup method you should use:
m_MoneyBox = new MoneyBox(); //GOOD
m_TextBox = new TextBox(); //GOOD
instead of
MoneyBox m_MoneyBox = new MoneyBox(); //BAD
TextBox m_TextBox = new TextBox(); //BAD
Just for anyone that could need it again
Related
I am struggling with passing a Variable (a string) in C# for a special problem:
Overview:
I am writing a plugin for a purchased program at my company. The program (or better: the programs support) gives the user basic C#-Code which basically just opens a form, and connects the program with whatever I write down in the forms code.
As it is a Visual-Studio-Solution I get some files: "MyUserInterface.cs" and "MyUserInterface.Designer.cs".
"MyUserInterface.Designer.cs" defines the look of my form, i thing the most importand parts for my problem are:
partial class MyUserInterface
{
[...]
private void InitializeComponent()
{
[...]
this.f_status = new System.Windows.Forms.Label();
this.SuspendLayout();
[...]
//
// status
//
this.f_status.Name = "status";
this.f_status.Text = "WELCOME TO MYPLUGIN v2";
[...]
this.Controls.Add(this.f_status);
this.ResumeLayout(false);
this.PerformLayout();
}
[...]
private System.Windows.Forms.Label f_status;
[...]
}
The most important code from "MyUserInterface.cs" is:
partial class MyUserInterface
{
[...]
public MyUserInterface()
{
InitializeComponent();
}
[...]
private void click_compute(object sender, EventArgs e)
{
//Basically everythings runs here!
//The code is opend in other classes and other files
}
}
Now as i marked in the code section, my whole code runs in the "click-compute" Function and is "outsourced" into other classes.
One important part of my code is found in "statushandler.cs":
class statushandler
{
[...]
public static void status_msg(string c_msg)
{
[...]
f_status.Text = c_msg; // And here is my problem!!
[...]
}
}
Problem:
In my special case, i try to change the text of the "f_status"-Lable while running my code by using the "status_msg" Function!
While I pass variables between classes a few times in my code. A cannot figure out, why this explicit one cant be found inside "statushandler". (It is no problem as long as I stay inside the original "click_compute", without going into a different class).
What I already tried:
1.) I tried to change basically everything in "MyUserInterface" into "public",
2.) Also I tried to call f_status in status_msg like MyUserInterface.f_status.Text,
3.) Write a Getter/Setter-Function in "MyUserInterface.(Designer.)cs" (both), which was catastrophic because i couldn't define the Label in the InitializeComponent anymore.
4.)
a.)Read a lot of Stackoverflow-Threads about passing variables between classes, which all didn't helped, all solutions I found, are working between classes, but not in this special case.
b.)Watched a lot of youTube tutorials, same result.
c.)Read some stackoverflow-Threds about passing variables between different Forms, but they all had in common, that the "displaying-form" was opend AFTER the variable was known. In my special case the form is opened all the time, and can't be closed, nor reopened...
And now I am out of ideas!
I wouldn't be surprised, if I do not see some details, but I can't found them... I would be very happy, when somebody could help me!
My question:
How can I change the text of my lable from another class?
Your method is static while your form has instance. So your static method does not know anything about your form. You can add MyUserInterface parameter to static method
public static void status_msg(MyUserInterface form, string c_msg)
{
[...]
form.f_status.Text = c_msg; // And here is my problem!!
[...]
}
If you have single instance form (only one instance is created at a time) you can have static property with it's reference:
partial class MyUserInterface
{
public static MyUserInterface Instance { get; private set; }
[...]
public MyUserInterface()
{
InitializeComponent();
Instance = this;
}
}
With this solution you can use your old method:
class statushandler
{
[...]
public static void status_msg(string c_msg)
{
[...]
MyUserInterface.Instance.f_status.Text = c_msg; // You have instance of yout form here
[...]
}
}
Of course you should protect against null/ Disposed form etc.
Create a public property on the specific class in your 1st Form that gets the label's value like this:
public string Name {get {return Label1.Text}; set {Label1.Text = value}; }
Then in your 2nd Form:
public Form2(Form1 form)
{
string name;
name = form.Name;
}
I'm creating a library which relies on capturing the SynchronizationContext in order to post callbacks back to the UI thread.
A user was having a weird condition where the callbacks were being posted to the ThreadPool instead. After investigating a bit, I came up with the following two test cases:
1:
public partial class Form1 : Form
{
private Test test;
public Form1()
{
test = new Test();
InitializeComponent();
}
private class Test
{
public Test()
{
if (SynchronizationContext.Current == null)
throw new InvalidOperationException("It's null! :(");
}
}
}
2:
public partial class Form1 : Form
{
private Test test = new Test();
public Form1()
{
InitializeComponent();
}
private class Test
{
public Test()
{
if (SynchronizationContext.Current == null)
throw new InvalidOperationException("It's null! :(");
}
}
}
The 1st test runs fine, but the 2nd one throws an exception. Why?
In the second example new Test() runs (almost) as the very first code in the program. Probably, your Main function calls new Form1() which immediately calls new Test().
A SynchronizationContext must be set before it is present (obviously). There is nothing magic in the runtime that guesses that your app will use WinForms. Using WinForms is a dynamic runtime decision. WinForms will set its SynchronizationContext when you use WinForms (I forgot the exact trigger points).
In the first example the base constructor (new Form()) runs first which apparently installs the SynchronizationContext.
When you run code before any WinForms code runs no SynchronizationContext will/can be present.
There is nothing sane that your library can do about this. You could add an assert or manually set the WinForms sync context (there is a API for that) but that is hardly the business of a library. Libraries are not supposed to mess with global state. (Except if your library is clearly meant for WinForms-only use).
Im trying to test a method which composes a collection of controls. It calls two methods:
Copies the original collection.
Sorts the new collection.
Ideally id like to be able to pass in a collection and test to see thats it sorts it correctly. Id also like to verify that method 1) is called twice, see below attempt based on the following:
Example using RhinoMock
The following test is producing errors when i try to create an instance of MainPresenter. General jist of the errors are "Can not convert from Moq.Mock to "FrazerMann.CsvImporter.UserInterface.IMainForm. + a similar one for IFileDialog.
[Test]
public void ComposeCollectionOfControls_CallSequence_4Calls()
{
var main = new Mock<IMainForm>();
var dialog = new Mock<IFileDialog>();
var temp = new Mock<IMainPresenter>();
temp.Setup(s => s.PopulateLists<Control>(It.IsAny<TableLayoutPanel>(), It.IsAny<List<Control>>()));
var testObject = new MainPresenter(main.Object, dialog.Object);
testObject.ComposeCollectionOfControls(It.IsAny<object>(), It.IsAny<EventArgs>());
temp.Verify(v => v.PopulateLists<Control>(It.IsAny<TableLayoutPanel>(), It.IsAny<List<Control>>()), Times.Once());
}
I would like to test the ComposeCollectionOfControls to ensure PopulateList() is called twice.
public interface IMainPresenter
{
void PopulateLists<T>(TableLayoutPanel userInputs, List<T> container) where T : Control;
int SortList<T>(T control1, T control2) where T : Control;
}
public class MainPresenter:IMainPresenter
{
UserInputEntity inputs;
IFileDialog _dialog;
IMainForm _view;
public MainPresenter(IMainForm view, IFileDialog dialog)
{
_view = view;
_dialog = dialog;
view.ComposeCollectionOfControls += ComposeCollectionOfControls;
view.SelectCsvFilePath += SelectCsvFilePath;
view.SelectErrorLogFilePath += SelectErrorLogFilePath;
view.DataVerification += DataVerification;
}
public void ComposeCollectionOfControls(object sender, EventArgs e)
{
PopulateLists<TextBox>(_view.ColumnNameCtrls, _view.SortedColumnNameCtrls);
_view.SortedColumnNameCtrls.Sort(SortList<TextBox>);
PopulateLists<ComboBox>(_view.ColumnDataTypeCtrls, _view.SortedColumnDataTypeCtrls);
_view.SortedColumnDataTypeCtrls.Sort(SortList<ComboBox>);
}
}
Could someone please give me some pointers as to how this should be done?
The error you are seeing is because your are passing the mock class itself (which is of type Moq.Mock) rather than the mocked object that Moq creates for you.
Instead of:
var testObject = new MainPresenter(main, dialog);
you need:
var testObject = new MainPresenter(main.Object, dialog.Object);
As an aside, it is usually considered bad practice to explicitly verify things like the number of calls made on a particular method. This leads to a tight coupling between your tests and a particular implementation, and consequently brittle tests.
By testing how many times you call a method you will often find a test failing after you refactor some code when the end result of the code is still correct.
It is much better to test the final state of the objects involved, and make your tests ignorant of how that state was reached.
UPDATE: I've changed the wording of the question. Previously it was a yes/no question about if a base class could be changed at runtime.
I may be working on mission impossible here, but I seem to be getting close. I want to extend a ASP.NET control, and I want my code to be unit testable. Also, I'd like to be able to fake behaviors of a real Label (namely things like ID generation, etc), which a real Label can't do in an nUnit host.
Here a working example that makes assertions on something that depends on a real base class and something that doesn't-- in a more realistic unit test, the test would depend on both --i.e. an ID existing and some custom behavior.
Anyhow the code says it better than I can:
public class LabelWrapper : Label //Runtime
//public class LabelWrapper : FakeLabel //Unit Test time
{
private readonly LabelLogic logic= new LabelLogic();
public override string Text
{
get
{
return logic.ProcessGetText(base.Text);
}
set
{
base.Text=logic.ProcessSetText(value);
}
}
}
//Ugh, now I have to test FakeLabelWrapper
public class FakeLabelWrapper : FakeLabel //Unit Test time
{
private readonly LabelLogic logic= new LabelLogic();
public override string Text
{
get
{
return logic.ProcessGetText(base.Text);
}
set
{
base.Text=logic.ProcessSetText(value);
}
}
}
[TestFixture]
public class UnitTest
{
[Test]
public void Test()
{
//Wish this was LabelWrapper label = new LabelWrapper(new FakeBase())
LabelWrapper label = new LabelWrapper();
//FakeLabelWrapper label = new FakeLabelWrapper();
label.Text = "ToUpper";
Assert.AreEqual("TOUPPER",label.Text);
StringWriter stringWriter = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(stringWriter);
label.RenderControl(writer);
Assert.AreEqual(1,label.ID);
Assert.AreEqual("<span>TOUPPER</span>", stringWriter.ToString());
}
}
public class FakeLabel
{
virtual public string Text { get; set; }
public void RenderControl(TextWriter writer)
{
writer.Write("<span>" + Text + "</span>");
}
}
//System Under Test
internal class LabelLogic
{
internal string ProcessGetText(string value)
{
return value.ToUpper();
}
internal string ProcessSetText(string value)
{
return value.ToUpper();
}
}
This is simply not possible in .Net. You cannot alter compiled meta-data on the fly.
Think of all of the havoc this would cause. Pretend I had the following situation
class Example {
Label l = new LabelWrapper();
}
This code has executed and suddenly your code runs that switches the base type of LabelWrapper to be FakeLabel. This raises a number of very hairy problems, including but not limited to
What would happen to existing instances of Example?
What would happen to new instances of Example as this code is now completely invalid?
Number of security nightmares this introduces as I can now mutate my object on the fly in a way APIs can't account for.
I do not understand your example quite well. But if you want to partially change the behavior of your LabelWrapper for unit tests, you could use Moq.
Moq is a Mocking framework which allows to setup your Mock with specific behavior on selected methods. This would mean you would test a mocked version of your LabelWrapper which is quite unconventional, however.
Im in the process of writing a test for a small application that follows the MVP pattern.
Technically, I know I should have written the test before the code, but I needed to knock up a demo app quick smart and so im now going back to the test before moving on to the real development.
In short I am attempting to test the presenter, however I cannot even get an empty test to run due to an Internal.ExpectationException.
The exception is raised on a unexpected invocation of an event assignation.
Here is the presenter class,
public LBCPresenter(IView view, IModel model)
{
m_model = model;
m_model.BatteryModifiedEvent += new EventHandler(m_model_BatteryModifiedEvent);
}
Model Interface
public interface IModel
{
event EventHandler BatteryModifiedEvent;
}
And here is the test class, I can't see what im missing, ive told NMock to expect the event...
[TestFixture]
public class MVP_PresenterTester
{
private Mockery mocks;
private IView _mockView;
private IViewObserver _Presenter;
private IModel _mockModel;
[SetUp]
public void SetUp()
{
mocks = new Mockery();
_mockView = mocks.NewMock<IView>();
_mockModel = mocks.NewMock<IModel>();
_Presenter = new LBCPresenter(_mockView, _mockModel);
}
[Test]
public void TestClosingFormWhenNotDirty()
{
Expect.Once.On(_mockModel).EventAdd("BatteryModifiedEvent", NMock2.Is.Anything);
//makes no difference if following line is commented out or not
//mocks.VerifyAllExpectationsHaveBeenMet();
}
}
Every time I run the test I get the same expectation Exception.
Any ideas?
I think its a timing issue - you are calling the presenter constructor in the test Setup - this means the event add is happening before your test sets up the EventAdd expectation.
If you move your call to the presenter constructor below the EventAdd expection it should work