I use SpecFlow with Coded UI to create some automated functional tests for a WPF application. Test case execution is performed using MsTest and Visual Studio Premium 2012.
I have a lot of test cases. If I execute them one by one everything is OK. If I put them all in an ordered test I receive the following error:
Microsoft.VisualStudio.TestTools.UITest.Extension.UITestControlNotAvailableException: The following element is no longer available: Name [], ControlType [Custom], AutomationId [reags:LoadView_1], RuntimeId [7,1620,64780193] ---> System.Windows.Automation.ElementNotAvailableException: The following element is no longer available: Name [], ControlType [Window], AutomationId [UnitializedCB3702D1-14B6-4001-8BC7-CD4C22C18BE1], RuntimeId [42,1770052]
at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaUtility.MapAndThrowException(SystemException e, IUITechnologyElement element)
at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.get_AutomationId()
at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.HasValidAutomationId()
at Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.UiaElement.get_FriendlyName()
at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillPropertyFromUIElement(UIObject obj, IUITechnologyElement element)
at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillPropertyOfTopLevelElementFromUIElement(UIObject obj, IUITechnologyElement element)
at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.FillTopLevelElementFromUIElement(IUITechnologyElement element, TopLevelElement obj, Boolean stripBrowserWindowTitleSuffix)
at Microsoft.VisualStudio.TestTools.UITest.Common.UIMap.UIMapUtil.GetCompleteQueryId(UITechnologyElement pluginNode)
at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetQueryIdForCaching()
at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.<>c__DisplayClass6.<CacheQueryId>b__5()
at Microsoft.VisualStudio.TestTools.UITesting.CodedUITestMethodInvoker.InvokeMethod[T](Func`1 function, UITestControl control, Boolean firePlaybackErrorEvent, Boolean logAsAction)
at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.CacheQueryId(String queryId)
at Microsoft.VisualStudio.TestTools.UITesting.UITestControl..ctor(IUITechnologyElement element, UITestControl searchContainer, String queryIdForRefetch)
at Microsoft.VisualStudio.TestTools.UITesting.TechnologyElementPropertyProvider.GetPropertyValue(UITestControl uiControl, String propertyName)
at Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.TryGetPropertyFromTechnologyElement(UITestControl uiControl, String propertyName, Object& value)
at Microsoft.VisualStudio.TestTools.UITesting.PropertyProviderBase.GetPropertyValue(UITestControl uiControl, String propertyName)
at Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.GetPropertyValueWrapper(UITestControl uiControl, String propertyName)
at Microsoft.VisualStudio.TestTools.UITesting.UITestControl.GetPropertyValuePrivate(String propertyName)
The first couple of errors were fixed using this hint, but I have some auto-generated steps and in order to re-search the controls I have to move the code and... a lot of unnecessary and annoying work.
Could you suggest some another solution to fix this? Is there some trick with the ordered tests? Or some nice clean-up methods for problems like this?
Thanks!
Here's what I did with a recent project.
First I created some CodedUI test methods as if SpecFlow didn't exist so I could keep those layers separate. Then I created step definition classes in C# that delegate to the coded UI test methods I created.
In a before scenario hook I created my UIMap instances (the classes generated by the CodedUI test generator) so each scenario had a fresh instance of my UIMap classes. You need this because object references in these classes are cached. Each new screen in your app is a whole new object tree that CodedUI must traverse.
Many times my step definitions just dive right into the CodedUI API to create custom searches, and I used the auto generated methods in my UIMap classes as a point of reference.
A little elaboration on how I set up my test project.
About My Test Project
I created a new "Test" project in Visual Studio 2010, which references the following libraries:
Microsoft (probably comes with default Test project template)
Microsoft.VisualStudio.QualityTools.CodedUITestFramework
Microsoft.VisualStudio.QualityTools.UnitTestFramework
Microsoft.VisualStudio.TestTools.UITest.Common
Microsoft.VisualStudio.TestTools.UITest.Extension
Microsoft.VisualStudio.TestTools.UITesting
UIAutomationTypes
NuGet Packages
AutoMapper
AutoMapper.Net4
SpecFlow.Assist.Dynamic
TechTalk.SpecFlow
Test Project Structure
This was my first stab at CodedUI Tests. I came from a Ruby on Rails background, and did a fair amount of reading online about implementing CodedUI Tests and SpecFlow tests. It's not a perfect setup, but it seems to be pretty maintainable for us.
Tests (Test project)
Features/
Bar.feature
Foo.feature
Regression/
Screen1/
TestsA.feature
TestsB.feature
StepDefinitions/
CommonHooks.cs
DataAssertionSteps.cs
DataSteps.cs
FormSteps.cs
GeneralSteps.cs
PresentationAssertionSteps.cs
Screen1Steps.cs
Screen2Steps.cs
UI/
FormMaps/
Screen1FormMap.cs
Screen2FormMap.cs
UIMapLoader/
User.cs
UIMap.uitest (created by CodedUI test framework)
Models (C# Class Library Project)
Entities/
Blog.cs
Comment.cs
Post.cs
Repositories/
BlogRepository.cs
CommentRepository.cs
PostRepository.cs
ViewModels/
Screen1ViewModel.cs
Screen2ViewModel.cs
Tests/Features
This folder contains all the SpecFlow feature files implementing the basic business rules, or acceptance tests. Simple screens got their own feature file, whereas screens with more complex business logic were broken into multiple feature files. I tried to keep these features friendly to read for both Business and Developers.
Tests/Regression
Because our Web Application was not architected in a manor allowing unit testing, all of our testing must be done through the UI. The Tests/Regressions folder contains all the SpecFlow feature files for our full regression of the application. This includes the really granular tests, like typing too many characters into form fields, etc. These features weren't really meant as business documenation. They are only meant to prevent us from being woken up at 3 a.m. because of production problems. Why do these problems always happen at 3 a.m.? ...
Tests/StepDefinitions
The Test/StepDefinitions folder contains all the SpecFlow Step Definition files. I broke these files down first into common steps, and then steps pertaining to a particular screen in my application.
CommonHooks.cs -- Created by SpecFlow
[Binding]
public class CommonHooks
{
[BeforeTestRun]
public static void BeforeTestRun()
{
...
}
[BeforeScenario]
public void BeforeScenario()
{
User.General.OpenLauncher();
}
[AfterScenario]
public void AfterScenario()
{
User.General.CloseBrowser();
User.General = null;
}
}
The BeforeScenario and AfterScenario methods are where I create and/or destroy instances of the CodedUI UIMap classes (More on that further down)
DataAssertionSteps.cs -- Step definitions asserting that data shows up, or doesn't show up in the database. These are all Then ... step definitions.
Scenario: Foo
Then a Foo should exist
In DataAssertionSteps.cs:
[Then(#"a Foo should exist")]
public void ThenAFooShouldExist()
{
// query the database for a record
// assert the record exists
}
DataSteps.cs -- Steps to seed the database with data, or remove data. These are all Given ... step definitions used to set up a scenario.
FormSteps.cs -- Step definitions for interacting with forms. These all tend to be When I ... steps
GeneralSteps.cs -- Realy generic step definitions. Things like When I click the "Foo" link go here.
PresentationAssertionSteps.cs -- Generic steps asserting that the UI is behaving properly. Things like Then I should see the text "Foo" go here.
Screen1Steps.cs -- When I needed steps for a particular screen, I created a step definition file for that screen. For example, if I needed steps for the "Blog Post" screen, then I created a file call BlogPostSteps.cs, which contained all those step definitions.
Tests/UI
The Tests/UI folder contains a bunch of custom written C# classes that we used to map label text found in our *.feature files to the names of form controls. You might not need this layer, but we did. This makes it easier to refactor your test project if form control names change, and especially for Web Projects because the HTML form field names change based on the <asp /> containers in our ascx files.
Example class:
namespace Tests.UI.FormMaps.Screen1FormMap
{
public static IDictionary<string, string> Fields = new Dictionary<string, string>()
{
{ "First Name", "UserControlA_PanelB_txtFirstName" },
{ ... },
...
};
}
Example Step:
When I enter "Joe" in the "First Name" textbox in the "Screen 1" form
Example Step Definition:
[When(#"I enter ""(.*)"" in the ""(.*)"" textbox in the ""(.*)"" form")]
public void WhenIEnterInTheTextboxInTheForm(string text, string labelText, string formName)
{
if (formName == "Screen 1")
{
// form control name: Screen1FormMap.Fields[labelText]
}
...
}
The step definition then used the Tests.UI.FormMaps.Screen1FormMap.Fields property to retrieve the form control name based on the label text in the *.feature files.
Tests.UI.FormMaps.Screen1FormMap.Fields["First Name"]
Tests/UI/UIMapLoader/User.cs
The other thing inside this folder is the UI/UIMapLoader/User.cs file. This class is a custom written class providing easy access to all the UIMap classes generated by the CodedUI Test framework.
namespace Tests.UI.UIMapLoader
{
public static class User
{
private static UIMap _general;
public static UIMap General
{
get { return _general ?? (_general = new UIMap()); }
set { _general = value; }
}
}
}
That way the Step Definition classes can easily access the UI maps via:
User.General.SomeCodedUITestRecordedMethod(...);
You saw a reference to this class in the BeforeScenario and AfterScenario methods in the CommonHooks.cs file referenced above.
Models Project
This is just a class lib to encompass the entities and repositories allowing the test project to access the database. Nothing special here except the ViewModels directory. Some of the screens have complex relationships with data in the database, so I created a ViewModel class to allow my SpecFlow step definitions to easily seed the database with data for these screens.
Related
Created a new "WPF Application" .NET 6.0 project
There creating classical Application Settings was easy in project->properties->Settings->"Create or open application settings"
Observed: the project gets a new folder "Properties" which has a yellow Folder icon with an additional black wrench symbol, okay
It contains a new item Settings.settings that can get edited via classical Settings Designer looking like it used to look in .Net 4.8, and a new App.config XML file is getting created automatically in the project's root folder which also looks like it used to in .Net 4.8, okay
Now the same procedure can apparently only be done manually in
a new "Class Library" project being added in the same solution where I would want to use that Properties.Settings / app.config feature pack for storing a DB connection string configurably:
the new sub-project does not seem to have a "Settings" option in the project Properties dialog (as opposed to a .Net4.x would have had)
the new Properties folder and new Settings file can be created successfully there too manually as described in Equivalent to UserSettings / ApplicationSettings in WPF .NET 5, .NET 6 or .Net Core
but doing a "Rebuild solution" gives an
Error CS1069 The type name 'ApplicationSettingsBase' could not be found in the namespace 'System.Configuration'. This type has been forwarded to assembly 'System.Configuration.ConfigurationManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' Consider adding a reference to that assembly. ClassLibrary1 C:\Users\Stefan\source\repos\WpfCorePropertiesSettings\ClassLibrary1\Properties\Settings.Designer.cs 16 Active
as a next step adding NuGet package "System.Configuration.Abstractions" to the Class Library project cures the symptom, "rebuild solution" makes the error disappear.
TLDNR, actual question: is that sequence an acceptable solution or a kludge to avoid?
To me the NuGet package description does not sound as if the package was made for that purpose, and I have not heard the maintainers' names before (which might or might not matter?)
https://github.com/davidwhitney/System.Configuration.Abstractions
TIA
PS:
Maybe I don't understand something...
Why create "Equivalent to UserSettings"?
My configuration is Win10+VS2022. I am creating a WPF .Net6 project. I go to the "Project Properties" menu. In the menu of the project properties tab (column on the left) there is an item Options. When selected, if the settings have not yet been created, there will be a small comment and a link to "Open or create application settings".
Unfortunately, I have Russian localization, so the screenshots are with Russian names.
Addition
But an additional "Class Library" sub-project does not seem to have that Project Properties option in my En/US localization. Does it in yours?
These are the APP settings.
Therefore, they do not make much sense in the library.
But if you need to, you can just copy the class to the library and then set up the links you need.
To do this, type in the application code the line Properties.Settings.Default.Save();. Move the cursor to Settings and press the F12 key.
You will be taken to the source code for the Settings class declaration. This code is generated by a code generator.
After moving to, copy all the source code into a class in another project. After the migration, you may need to add references in the project, fix the namespace and add usings.
As for the parameters in the «Class Library» project, it probably depends on what type this library is.
I have such settings in the «Class Library for WPF».
But in Libraries for Standard - no.
In the meantime I'm happy with a custom "AppSettings.json" approach.
After removing the previously described "classical app.config" approach, and after adding two NuGet packages:
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
... I created a custom Json file on "Class Library" (sub)project level in Visual Studio manually, and set its CopyToOutputDirectory property
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
And added an 'IConfigurationBuilder` part:
using Microsoft.Extensions.Configuration;
namespace Xyz.Data
{
internal class AppSettingsConfig
{
public AppSettingsConfig()
{
IConfigurationBuilder builder = new ConfigurationBuilder();
_ = builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "AppSettings.Movies3Data.json"));
var root = builder.Build();
AttachedDb = root.GetConnectionString("AttachedDb")!;
}
public string AttachedDb { get; init; }
}
}
And then made it a "Jon Skeet singleton"
/// <summary>
/// Singleton as described by Jon Skeet
/// </summary>
/// https://csharpindepth.com/Articles/Singleton
internal sealed class AppSettingsConfigSingleton
{
private static readonly Logger log = LogManager.GetCurrentClassLogger();
private AppSettingsConfigSingleton()
{
log.Trace($"{nameof(AppSettingsConfigSingleton)} ctor is running");
IConfigurationBuilder builder = new ConfigurationBuilder();
_ = builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "AppSettings.Movies3Data.json"));
var root = builder.Build();
AttachedDb = root.GetConnectionString("AttachedDb")!;
}
static AppSettingsConfigSingleton() { }
public string? AttachedDb { get; init; }
public static AppSettingsConfigSingleton Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly AppSettingsConfigSingleton instance = new();
}
}
And it "works well" by also reading JSON content just having been modified by admins at run-time. (Which would be the Entity Framework Core "localdb" location for the unit-of-work pattern in a multi-UI solution). Thanks again to you too, #EldHasp
I'm using NUnit + Webdriver + C#. Setup class has next stucture:
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(ChromeDriver))]
public partial class SetupBase<TWebDriver> where TWebDriver : IWebDriver, new()
{
public IWebDriver _driver;
[OneTimeSetUp]
public void OneTimeSetUp()
{
Init();
}
}
How can I set name of tests to include methode name, arguments and name of browser?
I tried with capabilities but it didn't help
ChromeOptions options = new ChromeOptions();
options.AddAdditionalCapability("Name", String.Format ("{0}_Chrome", TestContext.CurrentContext.Test.Name), true);
Also tried to use next code but was not able to find way how to pass driver type to NameAttribute
public class NameAttribute : NUnitAttribute, IApplyToTest
{
public NameAttribute(string name)
{
Name = String.Format("{0} {1}", name);
}
public string Name { get; set; }
public void ApplyToTest(Test test)
{
test.Properties.Add("Name", Name);
}
}
Can you help me please. Maybe need to update base class structure somehow?
This is how I use in tests
public class _001_General<TWebDriver> : SetupBase<TWebDriver> where TWebDriver : IWebDriver, new()
{
[OneTimeSetUp]
public void OneTimeSetupTest ()
{
//somework
}
[Test]
public void Test ()
{
//somework
}
}
Also SetupBase class contains functions that are used in tests
In NUnit, test cases, test methods, test fixtures and generic test fixture classes are all "tests" even though we sometimes talk loosely about "tests" as meaning test cases.
In your example, the following names are created:
_001_General<TWebDriver> (or maybe _001_General<>)
_001_General<InternetExplorerDriver>
Test
_001_General<ChromeDriver>
Test
Tests also have "fullnames", similar to that for a type or method. For example
_001_General<ChromeDriver>.Test
(Note: the fullname would also include a namespace, which I haven't shown.)
If you are using a runner that displays fullnames, like the NUnit 3 Console Runner, then there is no problem. So, I assume you are not. :-)
Some runners, like the NUnit 3 Visual Studio Test Adapter use simple test case names. So you would end up with a bunch of tests displayed with the name "Test."
Is that your problem? If so, this is not much of an answer. :-) However, I'll leave it as partial and add to it after hearing what runner you want to use and what you would like to see displayed in it.
UPDATE:
Based on your comment, what you really want to see is the test FullName - just as it is displayed by the NUnit 3 Console runner that TC runs for you. You'd like to see them in the VS IDE using the NUnit 3 VS Adapter.
Unfortunately, you can't right now. :-) More on that below. Meanwhile, here are some workarounds:
Use the console runner on your desktop. It's not as visual but works quite well. It's how I frequently work. Steps:
Install the console runner. I recommend using Chocolatey to install it globally, allowign you to use it with all your projects.
Set up your project to run the console runner with any options you like.
Make sure you use an external console window so you get the color display options that make the console runner easier to use.
Size your windows so you can see everything (if you have enough screen space) or just let the console run pop up on top of VS.
Try to trick VS by setting the test name in a way that includes the driver parameters. That's what you are already doing and it sounds as if you have already gotten almost all you can out of this option, i.e. class name without class parameters. You could try to take it a step further by creating separate classes for each driver. This would multiply the number of classes you have, obviously, but doesn't have to duplicate the code. You could use inheritance from the generic classes to create a new class with only a header in each place where it's needed. Like...
public class TestXYZDriver : TestDriver ...
This might be a lot of work, so it really depends on how important it is to you to get visual results that include fixture parameters right now.
For the future, you could request that the NUnit 3 Adapter project give an option of listing tests by their full names. I haven't worked on that project for a few years, so I'm not sure if it's actually possible. It may not be entirely in the control of the adapter, since VS controls what is displayed.
TL;DR: How do I combine info from two database tables into a Vaadin Treetable (or, when Vaadin 7.5 is released, a heirarchical Grid)?
I have a Java Swing desktop application that does this currently, albeit probably very ineffeciently with ArrayLists of Java Beans that updates from the SQL Server every 30 seconds. Well, I'm now attempting to port this desktop app over to a Vaadin web app. The desktop app has login capabilities and I'll eventually worry about doing the same for the web app, but for now, I just want to try and get the most basic part of this web app working: The Treetable. Or, hopefully soon, a heirarchical Grid.
To help illustrate what I'm aiming for, I'll try and post an image I created that should show how the data from the two tables needs to merge into the treetable (using a partial screenshot of my existing desktop app):
I am well aware of how to use the JOIN command in SQL and I've briefly read about Referencing Another SQLContainer, but I'm still in the early stages of learning Vaadin and still trying to wrap my head around SQLContainer, FreeformQuery, and how I need to implement FreeformStatementDelegate for my project. Not to mention that I'll need to implement checkboxes for each row, as you can see in that photo, so that it updates the database when they are clicked. And a semi-checked state for the checkbox would be necessary for Jobs that have more than one OrderDetail item wherein only some of those OrderDetail items are completed. To get that working for my Java Swing program, I had to lean on an expert Java developer who already had most of the code ready, and boy, is it super-complicated!
If anyone can give me a high-level view of how to accomplish this task along with some examples, I would be indebted. I totally understand that I'm asking for a great deal here, and I'm willing to take it slow, step-by-step, as long as you are. I really want to fully understand this so I'm not just copy-pasting code without thinking.
I have never used SQLContainer so this might not be the answer you want. I just had a quick look at SQLContainer and I'm not sure if it will serve your purpose. For a TreeTable you will need a Container Implementing the Container.Hierarchical interface or the table will put a wrapper around it and you have to set the parent-children relations manually. You probably could extend SQLContainer and implement the methods from Container.Hierarchical in that class but this might get complicated.
In your situation I think I'd go with implementing my own Container, probably extending AbstractContainer, to get the listener code for free, and implementing Hierarchical. There are quite some methods to implement, I know, and so this will need some time, but most methods are quickly implemented and you can start with the basic methods and add more interfaces (Ordered, Sortable, Indexed, Filterable, Collapsible,...) later.
If done properly you'll end up with with easy readable code that can be extended in the future without to much trouble and you will not depend on future versions of SQLContainer.
Another good thing is that you'll learn a lot about the data structures (Container, Item, Property) used in vaadin. But as I said I don't really know SQLContainer so maybe there will be a better answer telling you that it is easy with the SQLContainer
For the Checkbox feature you could go display the name/product property as a CheckBox. With Icon and Caption it looks almost like you want it. See http://demo.vaadin.com/sampler/#ui/data-input/other/check-box and set an Icon. The semi-checked state could be done with css.
Hope this helps you finding the right solution for your task.
I'll admit that I'm a beginner with vaadin myself and there may be much better ways of doing this, but here's something I've mocked up which seems to work. It doesn't do everything you need but it might be a base to start from. Most importantly, for changes to be saved back into the database you'll need to update the SQLContainers when something in the container is changed.
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.data.util.sqlcontainer.SQLContainer;
#SuppressWarnings("serial")
public class TwoTableHierarchicalContainer extends HierarchicalContainer {
private SQLContainer parentContainer;
private SQLContainer childContainer;
private String parentPrimaryKey;
private String childForeignKey;
public TwoTableHierarchicalContainer(SQLContainer parentContainer, SQLContainer childContainer,
String parentPrimaryKey, String childForeignKey) {
this.parentContainer = parentContainer;
this.childContainer = childContainer;
this.parentPrimaryKey = parentPrimaryKey;
this.childForeignKey = childForeignKey;
init();
}
private void init() {
for (Object containerPropertyIds : parentContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object containerPropertyIds : childContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object itemId : parentContainer.getItemIds()) {
Item parent = parentContainer.getItem(itemId);
Object newParentId = parent.getItemProperty(parentPrimaryKey).getValue();
Item newParent = addItem(newParentId);
setChildrenAllowed(newParentId, false);
for (Object propertyId : parent.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newParent.getItemProperty(propertyId);
newProperty.setValue(parent.getItemProperty(propertyId).getValue());
}
}
for (Object itemId : childContainer.getItemIds()) {
Item child = childContainer.getItem(itemId);
Object newParentId = child.getItemProperty(childForeignKey).getValue();
Object newChildId = addItem();
Item newChild = getItem(newChildId);
setChildrenAllowed(newParentId, true);
setParent(newChildId, newParentId);
setChildrenAllowed(newChildId, false);
for (Object propertyId : child.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newChild.getItemProperty(propertyId);
newProperty.setValue(child.getItemProperty(propertyId).getValue());
}
}
}
}
I have a simple standard repository that loads a composite entity from the database. It injects all dependencies it need to read the complete entity tree from a database through IDbConnection (wich gives the repository access to IDbCommand, IDbTransaction, IDataReader) that I could mock.
public class SomeCompositionRootEntityRepository :
IRepository<SomeCompositionRoot>
{
public RecipeRepository(IDbConnection connection) { ... }
public void Add(SomeCompositionRootEntity item) { ... }
public bool Remove(SomeCompositionRootEntity item) { ... }
public void Update(SomeCompositionRootEntity item) { ... }
public SomeCompositionRootEntity GetById(object id) { ... }
public bool Contains(object id) { ... }
}
The question is how would I write unit test for this in a good way? If I want to test that the reposity has read the whole tree of objects and it has read it correcty, I would need to write a hughe mock that records and verifies the read of each and every property of each and every object in the tree. Is this really the way to go?
Update:
I think I need to refactor my repository to break the repository functionality and unit test into smaller units. How could this be done?
I am sure I do not want to write unit test that involve reading and writing from and to an actual database.
The question is: What functionality do you want to test?
Do you want to test that your repository actually loads something? In this case I would write a few (!) tests that go through the database.
Or do you want to test the functionality inside the repository methods? In this case your mock approach would be appropriate.
Or do you want to make sure that the (trivial) methods of your repository aren't broken? In this case mocks and one test per method might be sufficient.
Just ask yourself what the tests shall ensure and design them along this target!
I think I understand your question so correct me if I'm wrong...
This is a where you cross the line from unit to integration. The test makes sense (I've written these myself), but you're not really testing your repository, rather you're testing that your entity (SomeCompositionRoot) maps correctly. It isn't inserting/updating, but does involve a read to the database.
Depending on what ORM you use, you can do this a million different ways and typically its fairly easy.
::EDIT::
like this for linq for example ...
[TestMethod]
public void ShouldMapBlahBlahCorrectly()
{
CheckBasicMapping<BlahBlah>();
}
private T CheckBasicMapping<T>() where T : class
{
var target = _testContext.GetTable<T>().FirstOrDefault();
target.ShouldNotBeNull();
return target;
}
I have a silverlight 2 app that has an ObservableCollection of a class from a separate assem/lib. When I set my ListBox.ItemsSource on that collection, and run it, I get the error code:
4004 "System.ArgumentException: Value does not fall within the expected range."
Here is part of the code:
public partial class Page : UserControl
{
ObservableCollection<Some.Lib.Owner> ooc;
public Page()
{
ooc = new ObservableCollection<Some.Lib.Owner>();
Some.Lib.Owner o1 = new Some.Lib.Owner() { FirstName = "test1" };
Some.Lib.Owner o2 = new Some.Lib.Owner() { FirstName = "test2" };
Some.Lib.Owner o3 = new Some.Lib.Owner() { FirstName = "test3" };
ooc.Add(o1);
ooc.Add(o2);
ooc.Add(o3);
InitializeComponent();
lb1.ItemsSource = ooc;
}
}
But when I create the Owner class within this same project, everything works fine.
Is there some security things going on behind the scenes? Also, I'm using the generate a html page option and not the aspx option, when I created this Silverlight 2 app.
Are you trying to use a standard class library or a "Silverlight Class Library"?
Because Silverlight 2 uses a subset of the CLR it cannot access standard class libraries that were compiled using the full CLR. To use an external assembly you must create it as a "Silverlight Class Library". This will create a project that only includes the namespaces available to Silverlight and will allow you to reference the assembly within your Silverlight project.
Check out the MSDN article ".NET Framework Class Library for Silverlight" for more info.
It may be because you're not handling a failure in SubmittedChanges(). See http://www.scottleckie.com/2010/04/code-4004-unhandled-error-in-silverlight-application/ for more info
Everything is in one project now.
Yes, but not like you just did it, instead, share, link to the file(s).
For this an old jedi mind trick of Silverlight when there is a need to share common entity code between the app and the service. This is done when the library could not be brought in due to the differences in .Net/CLR.
The trick is to include the file as a link into the other project. Here is how
In the target (Silverlight project) folder which needs the code file, right click and select Add then Existing Item... or shift alt A.
Browse to the location of the origins file(s) found and select the/those file(s).
Once the item(s) have been selected, then on the Add button select the drop down arrow.
Select Add as link to add the file(s) as a link into the folder.
Once done, there is only one copy, but built in two different places.
That will give access to the file as if the file was actually within the project's folder, but the file physically resides elsewhere...and avoids CLR issues.