Page 1 of 10 in the SharePoint-es category Next Page
Muchos de los desarrolladores de SharePoint, terminan optando por desplegar sus
aplicaciones en el GAC, para evitar problemas de seguridad. Esta no es la manera
más correcta y cada vez más administradores de sistemas, exigen que las
soluciones se desplieguen en los directorios de aplicación.
Los ensamblados que se ejecutan desde el GAC, se ejecutan bajo total confianza
(Full Trust) y están disponibles para todos los servidores virtuales y todas las
aplicaciones, lo cual termina siendo menos seguro si desconocemos la procedencia
del ensamblado, cosa que ocurre con frecuencia.
La seguridad de acceso al código nos permite restringir los tipos de recursos a
los cuales puede acceder el código así como las operaciones privilegiadas que
este puede realizar.
ASP.Net incluye cinco niveles de seguridad Full, High, Medium, Low, and Minimal.
(Completo, alto, medio, bajo y mínimo) estos niveles de seguridad los
establecemos en el web.config de nuestra aplicación web, bajo la etiqueta de
SecurityPolicy. (Las declaraciones de dichas políticas pueden verse en
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG)
SharePoint, añade dos políticas de seguridad personalizadas, WSS_Medium y
WSS_Minimal, (minima confianza, confianza media) cuyos archivos de política
pueden verse en (C:\Program Files\Common Files\Microsoft Shared\web server
extensions\12\CONFIG)
En el caso de WSS y MOSS, nuestro web.config comienza en
WSS_Minimal y conforme
vamos desplegando soluciones que incluyen políticas de acceso personalizadas
este archivo pasa a ser WSS_Custom.
Básicamente las diferencias establecidas entre los modelos WSS_Minimal y
WSS_Medium es que WSS_Minimal, no concede los permisos (DnsPermission,
EnvironmentPermission, FileIOPermission, IsolatedStorageFilePermission,
PrintingPermission, SharePointPermission, SmtpPermission, SqlClientPermission y
UIPermission)
Es decir, que con el modelo WSS_Minimal, no podemos realizar ninguna operación
de archivo, (leer/escribir), no podemos acceder a las variables de entrono o
acceder a datos … incluido el usar el modelo de objetos de SharePoint. Vamos, en una
palabra otorgamos la mínima confianza.
Recursos y permisos asociados
| Secure Resource |
Requires Permission |
| Data access |
SqlClientPermission OleDbPermission OraclePermission
|
| Directory services |
DirectoryServicesPermission |
| DNS databases |
DnsPermission |
| Event log |
EventLogPermission |
| Environment variables |
EnvironmentPermission |
| File system |
FileIOPermission |
| Isolated storage |
IsolatedStoragePermission |
| Message queues |
MessageQueuePermission |
| Performance counters |
PerformanceCounterPermission |
| Printers |
PrinterPermission |
| Registry |
RegistryPermission |
| Sockets |
SocketPermission |
| Web services (and other HTTP Internet resources) |
WebPermission |
| SharePoint Object Model |
SharePointPermission |
De modo que en nuestros archivos para el despliegue de soluciones de
SharePoint debemos incluir muestra política de seguridad definiendo nuestro CAS.
Evidentemente para muchos lo más fácil es indicar en el ensamblado
DeploymentTarget="GlobalAssemblyCache" con lo cual nuestro ensamblado ira a
parar al GAC obteniendo confianza total.
Para hacer un despliegue correcto y seguro, lo que debemos hacer es desplegar
nuestro ensamblado en el directorio bin de la aplicación web, DeploymentTarget="WebApplication"
y crear nuestra política de seguridad de código.
En el mismo archivo de solución, podemos indicar nuestra CAS :
<CodeAccessSecurity>
<PolicyItem>
<PermissionSet class="NamedPermissionSet"
version="1"
Description="Permisos para nuestro ensamblado">
<IPermission class="AspNetHostingPermission"
version="1"
Level="Minimal" />
<IPermission class="SecurityPermission"
version="1"
Flags="Execution" />
<IPermission class="Microsoft.SharePoint.Security.SharePointPermission,
Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1"
ObjectModel="True"
Impersonate="True"
Unrestricted="True" />
<IPermission class="System.Security.Permissions.SecurityPermission,
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Flags="ControlThread, Execution" />
</PermissionSet>
<Assemblies>
<Assembly Name="IdeSeg.SharePoint.WebParts.dll" />
</Assemblies>
</PolicyItem>
</CodeAccessSecurity>
Donde establecemos la política de seguridad de acceso, estableciendo nuestro conjunto personalizado de permisos.
Después debemos hacer el despliegue con STSADM -deploysolution solution -allowCasPolicies
Después de pasar algunas horas tratando de resolver un problema con las búsquedas incrementales en una instalación de MOSS, os recuerdo los hotfixes que han ido saliendo tras el SP1 el kb948945 ha solucionado el mio ...
En todas las instalaciones hay un punto crítico, esa pregunta que no tenemos muy clara y que en ocasiones va acompañada de un texto recomendando una de las opciones, por si no sabemos muy bien qué es lo que estamos haciendo. MOSS no es una excepción.
La pregunta en cuestión llega cuando tenemos que decidir sobre la seguridad, la instalación de MOSS nos da a elegir entre sí usaremos NTLM ó Kerberos.
Como todos sabemos y Microsoft dice NTLM funciona para casi todo. De modo que suele ser la opción preferida de todos. No hay que configurar nada y funciona. (http://support.microsoft.com/kb/832769)
Kerberos por el contrario es un sistema de autentificación un poco más complejo, pero también más seguro y más rápido (motivos por los cuales ya de por sí, debería ser la opción predilecta de todos)
Kerberos, es más rápido por que guarda en una cache (vales) la información del cliente después de que este se ha autentificado en el sistema, de modo que no tiene que estar comprobando las credenciales una y otra vez.
Otra de las características importantes de Kerberos es la Delegación, La delegación nos permite pasar las credenciales del cliente desde nuestro servidor front-end (SharePoint) a nuestros servidores back-end (SQL Server etc..).
Cuando usamos NTLM, y deseamos acceder a recursos que están fuera de nuestro alcance, podemos suplantar al cliente (impersonate) y usar la cuenta de suplantación para realizar las tareas necesarias.
¿Pero qué ocurre cuando tratamos de usar recursos que no están en la misma máquina que nuestro servidor web?, entonces la suplantación no es suficiente. Y se produce el efecto llamado Double-Hop (http://support.microsoft.com/default.aspx?scid=kb;en-us;329986)
Imaginemos que hemos realizado una solución para SharePoint que usa un servicio web o una conexión a un servidor SQL que se encuentra en una máquina distinta, y deseamos acceder usando la seguridad integrada (Integrated Security=SSPI) .
Al realizar la conexión nuestro servidor web debe ponerse en contacto con nuestro servidor SQL y este no es capaz de autentificar al usuario.
De modo que recibiremos un mensaje como:
Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.
Como mencionaba anteriormente, esto es debido a que la suplantación no es válida, necesitamos algo más; Delegación.
Y esa delegación aunque cueste un poquito más configurarla es la que nos ofrece Kerberos.
Este escenario se produce en multitud de instalaciones de MOSS en donde usamos servicios de Excel, para recuperar datos de los servicios de análisis de SQL.
Alguien me ha recordado que empecé a escribir sobre el tema de las pruebas
unitarias y finalmente no termine… o por lo menos no conté algunas de las
prácticas que uso… cierto. Parte 1 - Parte 2Básicamente la técnica que uso habitualmente consiste en aprovisionar un
sitio de forma automática. Y ¿Cómo se aprovisiona un sitio automáticamente?,
pues de la manera más sencilla posible. Usando Plantillas.
Provisión - Escenario de Pruebas
De modo que tengo distintas plantillas pre cargadas con listas, bibliotecas
de documentos, páginas etc… algunas incluyendo contenido, archivos, elementos de
las listas y un montón de cosas.
Es sencillísimo crear estos escenarios y pueden ser simples, incluyendo uno ó
unos pocos elementos ó complejos incluyendo una jerarquía de de sitios, en cuyo
caso crearemos una plantilla por cada sitio para más tarde reconstruir una
jerarquía de sitios determinada.
Después usamos un ayudante en nuestras pruebas para aprovisionar nuestros
sitios, un ejemplo de un aprovisionador de sitios básico sería algo como
esto, he recortado algunas cosas ...
public class SPProvisioningHelper { private const string DefaultWebName = "TestSite"; private readonly Dictionary<string, SPWeb> _webs;
private SPSite _site; private string _urlTestSite; public SPProvisioningHelper() { _webs = new Dictionary<string, SPWeb>(); UrlTestSite = "http://enjendro/unittests/"; }
// Url del sitio de pruebas
public string UrlTestSite { get { return _urlTestSite; } set { _urlTestSite = value; } }
// Coleccion de sitios sobre la que estamos trabajando
public SPSite Site { get { return _site; } }
// Una web determianda
public SPWeb GetWeb(string name) { return _webs[name]; }
// Provisiona una web vacia colgada de parentUrl
// Pruebas rápidas y de creación de elementos
public void WebProvisioning(string parentUrl) { _webs.Add(DefaultWebName, CreateWeb(DefaultWebName, parentUrl, string.Empty)); }
// Crea una web
public void WebProvisioning(string name, string parentUrl) { _webs.Add(name, CreateWeb(name, parentUrl, string.Empty)); }
// Crea una web basada en una plantilla
public void WebProvisioning(string name, string parentUrl, string template) { _webs.Add(name, CreateWeb(name, parentUrl, template)); }
// Crea las webs (hace el trabajo duro)
private SPWeb CreateWeb(string title, string parentUrl, string template) { Trace.WriteLine(string.Format("Creating test web {0} at {1}", title, parentUrl));
_site = new SPSite(UrlTestSite + parentUrl); SPWeb web = _site.OpenWeb(); SPWeb newWeb;
// Stop
if (web == null) { throw new SPException(string.Format("Can´t open SharePoint Site in: {0}", _site.Url)); }
// Si existe lo borramos
if (web.Webs[title].Exists) { RecursiveDeleteWebs(web.Webs[title]); web.Webs[title].Delete(); }
// Web vacio
if (template.Equals(string.Empty)) { newWeb = web.Webs.Add(title); } else
{
// web basado en plantilla personalizada
try { SPWebTemplateCollection webTemplateCollection; webTemplateCollection = _site.GetCustomWebTemplates((uint) web.Locale.LCID);
SPWebTemplate webTemplate = webTemplateCollection[template];
newWeb = web.Webs.Add(title, title, string.Empty, (uint) web.Locale.LCID, webTemplate, true, false); } // web basado en plantilla no personalizada
catch (ArgumentException) { newWeb = web.Webs.Add(title, title, string.Empty, (uint) web.Locale.LCID, template, true, false); } }
Trace.WriteLine(string.Format("Created web {0} at {1}", newWeb.Title, newWeb.Url));
return newWeb; }
// Limpieza
public void Clean() { DeleteWebs(); // Disposes
}
// Elimina las webs
private void DeleteWebs() { foreach (SPWeb web in _webs.Values) { RecursiveDeleteWebs(web); } }
// Elimina todo recursivamente
private void RecursiveDeleteWebs(SPWeb parentWeb) { // ...
}
}
Pruebas
Después en nuestras pruebas podemos inicializar los distintos escenarios, veamos un ejemplo usando el
aprovisionador anterior
[TestFixture] public class Tests { // El ayudante
private SPProvisioningHelper provisioningHelper;
[TestFixtureSetUp] public void Setup() { // Incializamos el ayudante
provisioningHelper = new SPProvisioningHelper(); // Ejemplos
// Aprovisionamos p1 desde una plantilla nuestra
provisioningHelper.WebProvisioning("p1", "P1", "Plantilla1.stp");
// jerarquia
provisioningHelper.WebProvisioning("p1", string.Empty);
// p1/p1a -> sitio de grupo
provisioningHelper.WebProvisioning("p1a", "p1", "STS");
// p1/p1b -> un blog
provisioningHelper.WebProvisioning("p1b", "p1", "Blog"); // p1/p1a/p1a1 -> un wiki
provisioningHelper.WebProvisioning("p1a1", "p1/p1a", "Wiki"); // p1/p1a/p1a1/p1a11 -> sitio en blanco
provisioningHelper.WebProvisioning("p1a11", "p1/p1a/p1a1"); }
// Una prueba simple
[Test]
public void GetCurrentUserName() { string expectedUser = WindowsIdentity.GetCurrent().Name;
SPUser user = provisioningHelper.GetWeb("p1").CurrentUser;
string userName = user.LoginName;
Trace.WriteLine(string.Format("Expected: {0} User: {1}", expectedUser, userName)); Assert.IsTrue(expectedUser.Equals(userName,StringComparison.OrdinalIgnoreCase)); }
// Limpieza
[TestFixtureTearDown]
public void TearDown() { provisioningHelper.Clean(); } }
Esto es básicamente, desde luego como ocurre con todos los sistemas que deben
ser aprovisionados, estos llevan su tiempo, en cualquier caso tampoco me parece
tanto y además hay unos estupendos quad core relativamente baratos así que no es
escusa para no tener una máquina de pruebas.
El martes 23 de Octubre, se celebra en Madrid la tercera conferencia de usuarios de SharePoint.
Si queréis asistir, debéis registraros con anterioridad, es imprescindible.
Por la mañana habrá diversas ponencias comentando casos prácticos de implantación y por la tarde sesiones técnicas. La agenda completa se puede consultar en este ENLACE.
10:00 Bienvenida y Situación General de SharePoint 10:20 Experiencia Criteria Caixa Corp 10:50 Experiencia Ancert - Agencia Notarial de Certificación 11:20 Experiencia Ministerio de la Presidencia 11:50 Descanso y café 12:20 Experiencia Caja Mediterráneo 12:50 Microsoft Office Sharepoint en Intenet - Web 2.0 - Silver Light 13:20 Búsqueda Empresarial - Search 13:40 Futuro de SharePoint 14:00 Almuerzo

Para más información llamar al 902322344 o un email a eventos.microsoft@sitel.es
Y podéis registraros AQUÍ.
Y el séptimo día, descansó
¿Pero? ¿Y si hubiera tenido que seguir un día tras otro y una semana tras otra? Más o menos lo que nos pasa a los desarrolladores, el trabajo nunca termina, con una línea completas un método, con un método una clase, con una clase un caso de uso un espacio de nombres, una biblioteca… siempre habrá detrás otra nueva clase, otra nueva biblioteca y así sin parar.
Un día tras otro… codificando, depurando, compilando, probando, no pongo meando porque a veces creo que me lo puedo hacer encima por no despegar los dedos del teclado …
Y a todo esto, cientos y cientos de tecnologías a nuestro alrededor que cambian constantemente, ¿y si a Dios le hubiesen cambiado las especificaciones una y otra vez?, y ¿si cada día hubiera tenido una nueva tecnología a su alcance?
Sinceramente, el mundo estaría por hacer. Sólo con el tiempo que lleva aprender, probar, crear un manual de buenas prácticas y realizar un framework adaptable y extensible y bla bla bla, para poder empezar a trabajar… estaría todavía diseñando a Adán.
Y eso gracias a que no dejo que Adán diera las especificaciones de Eva, porque todavía estaríamos esperando… (Lo digo sin ánimo de ser machista), porque estaríamos todavía en alguna iteración de la metodología divina, comprobando si el modelo cumple con las especificaciones del cliente.
En fin, si las cosas fueron así de rápidas supongo que serian por que no había, “cliente” y ¿si no había cliente?, ¿si no había especificaciones?, siempre me quedaré con la duda si se pudo hacer en 5 ó incluso en 4 días y se demoró el asunto. Digo yo, que siendo Dios, podía haberlo hecho todo en UNO, Mundo y Ploffff, toma MUNDO.
De modo que no me queda más que pensar que uso algún tipo de metodología para acometer el trabajo. ¿Cuál?, ¿Cómo hacer un mundo en 6 días y descansar el 7º? ó tal vez usó ¿Cómo hacer el mundo en 4 días y descansar 3?, desde luego que si uso esta no consiguió su objetivo, a pesar de la metodología.
Creo que nos quedaremos sin saberlo…
Volviendo al asunto, que en absoluto es la metodología, si no la gran cantidad de tecnologías de las que disponemos, y la gran cantidad de las que dispondremos en breve. Haciendo un pequeño resumen de las que necesitamos para desarrollar, pongamos por ejemplo SharePoint… un lenguaje .Net(C# ó VB.Net), Html, ASP.Net, XML, XSLT, JavaScript, Windows Workflow Foundation, InfoPath, TSQL, un SDK gordito y sin ejemplos, con más de 120Mb, 98 NameSpaces y 1.256 clases…
¿Sabéis una cosa? Yo quiero, que llegue el 7º Día.
Jhon Holliday (tambien MVP de SharePoint) lidera un proyecto llamado CAML.Net, que es una manera muy inteligente de integrar las consultas CAML en cualquier lenguaje .Net, con CAML.Net podemos mantener la estructura de las consultas de una manera intuitiva y natural, permitiéndonos construir componentes reusables. Además podemos realizar data-bindings con los resultados devueltos por las consultas, de manera brillante. Además está trabajando en un editor visual que tiene un aspecto excelente.
Podéis leer más sobre CAML.Net en:
Working with CAML.Net - Part 1 Working with CAML.Net - Part 2 (Introducing the CAML)
y el proyecto está en CodePlex http://codeplex.com/camldotnet
Yo he seguido jugando con YACAMLQT mi programita y he decidido adaptarlo para generar también CAML.Net.

YACAMLQT.zip (15,07 KB)
Update: Thanks to Cameron to report the Gq/Gt bug.
Como comentaba hace unos días, realizar pruebas unitarias usando mocks, no se siempre la mejor solución, personalmente, creo que no se debe abusar de ellos y usarlos para todo.
A continuación os cuento, como realizo mis pruebas unitarias cuando programo para SharePoint, seguramente no sean lo más idóneo del mundo, pero como dije en su día, no considero esto una ciencia sino más bien, un arte en donde cada uno utiliza aquello con lo que obtiene los mejores resultados, en cuanto a calidad. Siempre mantengo en mente el principio de que no deben llevar más trabajo que la realización del código.
El SDK de SharePoint, como comenté con anterioridad, es un framework con lo cual debemos dar por hecho algunas cosas, tenemos que tener claro que Microsoft, tomo ciertas decisiones en su diseño que por ende, nosotros no podemos cambiar.
SharePoint consta de un complejo modelo de objetos, en tres capas. De modo que cada vez que manipulamos estos, de forma transparente vamos cambiando la base de datos donde estos son persistidos. Esta cuestión es importante ya que es como si trabajásemos contra una base de datos y todos los que han realizado pruebas unitarias con bases de datos, saben la complejidad añadida que esto conlleva. Al margen de la discusión ya conocida sobre si las pruebas unitarias deben o no deben usar la base de datos como apunto Rodrigo.
Yo soy de la opinión de que mientras se pueda (por que se conoce) que base de datos se va a usar y podemos recrear un modelo de los datos sin un gran esfuerzo, es la mejor opción.
En SharePoint, aplico el mismo principio. Por diseño, la base de datos esta de manera subyacente así que la mejor manera de probar las cosas es usándola.
Mis pruebas con las Webparts
Las Webparts son un elemento dentro de SharePoint que nos permite interactuar con el usuario, a través del interface de usuario. En esta nueva versión como sabéis son los nativos de ASP.Net.
Como tales elementos, debemos confiar en que el comportamiento que tienen es el esperado, y me centro en realizar pruebas de la lógica subyacente, aquello que se encargará de producir los resultados en función de las entradas que reciba.
Veamos un simple ejemplo con un webpart que muestra el número de elementos que cumplen una condición en una lista. private string _list = string.Empty;
private string _message = string.Empty;
private string _query = string.Empty;
#region WEBPART PROPERTIES
[Personalizable(PersonalizationScope.Shared),
WebBrowsable,
Category("Settings"),
WebDisplayName("List Name")]
public string List
{
...
}
[Personalizable(PersonalizationScope.Shared),
WebBrowsable,
Category("Settings"),
WebDisplayName("CAML Query")]
public string Query
{
...
}
[Personalizable(PersonalizationScope.Shared),
WebBrowsable,
Category("Settings"),
WebDisplayName("Mesaage")]
public string Message
{
...
}
#endregion
protected override void Render(HtmlTextWriter output)
{
try
{
SPWeb web = SPControl.GetContextWeb(Context);
SPList list = web.Lists[List];
SPQuery query = new SPQuery();
query.Query = Query;
SPListItemCollection items = list.GetItems(query);
output.Write("<div>{0}<b>{1}</b></div>", Message, CountListItems(web, List, Query));
}
catch (Exception ex)
{
output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
}
}
Bien, aquí algunas buenas prácticas que suelo recomendar. Siempre que podamos debemos independizar nuestra lógica del componente, esto lo podemos hacer bien separando nuestro código en nuevos métodos: protected override void Render(HtmlTextWriter output)
{
SPWeb web = SPControl.GetContextWeb(Context);
try
{
output.Write("<div>{0}<b>{1}</b></div>", Message, CountListItems(web, List, Query));
}
catch (Exception ex)
{
output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
}
}
private int CountListItems(SPWeb web, string listName, string queryFiler)
{
SPList list = web.Lists[listName];
SPQuery query = new SPQuery();
query.Query = queryFiler;
SPListItemCollection items = list.GetItems(query);
return items.Count;
}
O lo que es mejor, aplicando los principios de delegación o composición para extraer las responsabilidades y la lógica a una nueva clase. protected override void Render(HtmlTextWriter output)
{
SPWeb web = SPControl.GetContextWeb(Context);
ListItemCounter listCounter = new ListItemCounter(web);
try
{
output.Write("<div>{0}<b>{1}</b></div>", Message, listCounter.CountListItems(List,Query));
}
catch (Exception ex)
{
output.Write(String.Format("<div>{0}: {1}</div>", ex.GetType(), ex.Message));
}
}
...
internal class ListItemCounter
{
private readonly SPWeb _web;
public ListItemCounter(SPWeb web)
{
_web = web;
}
public int CountListItems(string listName, string queryFiler)
{
SPList list = _web.Lists[listName];
SPQuery query = new SPQuery();
query.Query = queryFiler;
SPListItemCollection items = list.GetItems(query);
return items.Count;
}
}
Esto es importante ya que de este modo nuestro código quedará aislado de algunos de los elementos que el componente Webpart lleva implícitos, como el contexto en el cual la aplicación ASP.Net se está ejecutando; que entre otras cosas da bastante guerra ya que es complicado de reproducir. Y como consecuencia será más sencillo poder realizar las pruebas como veremos.
Estos días mi querido amigo Gustavo, ha estado pasando un infierno tratando de mejorar el proceso de realizar pruebas unitarias con SharePoint.
Desde mi punto de vista las pruebas con objetos Mock funcionan (luego veremos cómo), pero creo que no siempre son lo más adecuado y esto hay que tenerlo muy en cuenta.
Cuando desarrollamos pruebas unitarias tratamos de ver si existen diferencias entre el comportamiento esperado y el comportamiento observado. Cuando la realización de estas pruebas se convirtió en algo complejo, por la dependencia de nuestro código con sistemas externos surgieron distintas técnicas que nos permiten substituir estos sistemas e independizar nuestras pruebas.
Con estas técnicas, entre las cuales están los objetos Mock, el código que escribimos para realizar la prueba, interactúa con impostores, falsificaciones, espías, objetos simulados etc... Es decir con fantasmas.
Fantasmas, “ectoplasmas” que aparentan ser lo que no son; objetos de verdad. Pero que nos permiten entre otras cosas que nuestra prueba no se detenga por depender de un subsistema externo y muchas veces ajeno a nosotros.
De modo que en la mayoría de los casos, estamos dando por sentado como se comportará ese subsistema, comportamiento esperado. Al predeterminar esto estamos dando por hecho que dicho subsistema funcionará correctamente ó incorrectamente si queremos comprobar que nuestro código sabe responder a las fallas del subsistema, con lo que el subsistema real queda fuera del ámbito de nuestra prueba. Resumiendo, independizamos nuestras pruebas.
Veamos ahora un ejemplo conocido: public static class Tools
{
public static string GetCurrentUserName(HttpContext myContext)
{
SPWeb myWeb = SPControl.GetContextWeb(myContext);
SPUser myUser = myWeb.CurrentUser;
return myUser.LoginName;
}
}
Si, es enrevesado ya que estamos usando el contexto de la aplicación web (cosa que deberíamos evitar siempre que podamos, pero eso es otra historia)
Volviendo al código si lo que estamos haciendo es una aplicación ASP.Net que debe interactuar con SharePoint (el subsistema) y queremos realizar una prueba unitaria de este código podemos hacerlo usando objetos Mock.
De este modo nuestra prueba funcionará correctamente sin la necesidad de disponer de una instalación de SharePoint.
Yo personalmente uso TypeMock, que me parece sin lugar a dudas el más completo y con el que menos cuesta (en términos de líneas) realizar los test.
Ejemplo [Test]
public void GetCurrentUserNameTest()
{
string expectedUserName = "Sample User";
MockManager.Init();
// Hacemos un Mock de SPUser
// Usando MockManager.MockObject nos permitira crear un objeto sin
// llamar a su constructor para recuperar la instancia inmediatamente
MockObject mockSPUser = MockManager.MockObject(typeof (SPUser));
// Fijamos el valor que será devuelto cuando se solicite el valor de la
// propiedad LoginName
mockSPUser.ExpectGet("LoginName", expectedUserName);
// Devolvemos la instancia para poder usarla
SPUser spUser = mockSPUser.Object as SPUser;
// Hacemos un Mock de SPWeb
MockObject mockSPWeb = MockManager.MockObject(typeof (SPWeb));
// Fijamos el valor que será devuelto cuando se solicite el valor de la
// propiedad CurrentUser que es el objeto SPUser que creamos anteriormente
mockSPWeb.ExpectGet("CurrentUser", spUser);
// Devolvemos la instancia para poder usarla
SPWeb spWeb = mockSPWeb.Object as SPWeb;
// Hacemos un Mock de SPControl
// En esta ocasion no vamos a instanciarlo ahora, se instanciará automaticamente
// cuando se solicite
Mock mockSPControl = MockManager.Mock(typeof (SPControl));
// En cualquier caso el método GetContextWeb, devolverá el objeto SPWeb
mockSPControl.AlwaysReturn("GetContextWeb", spWeb);
// Tomamos el nombre del usuario
// Incluso podemos pasarle null (este no es el test de parametros/excepciones)
string userName = Tools.GetCurrentUserName(null);
// Comprobamos que el valor esperado es el valor que hemos obtenido
Assert.AreEqual(expectedUserName, userName, "Correct!!!");
// Verificamos la prueba
MockManager.Verify();
}
El código de la prueba nos permite verificar que el método GetCurrentUserName funciona correctamente. Es más no necesitamos depender de SharePoint para probar nuestro código. Ya somos independientes del Subsistema.
Pero si analizamos la prueba, lo único que hemos hecho es prefijar el comportamiento de cada uno de los objetos que usa nuestro método, que como dice un gran amigo, es como decirle al ordenador: Cuándo te pregunte como me llamo, di que me llamo PEPE, y preguntarle ¿Cómo me llamo? a lo cual responderá PEPE, y diremos BIEN, aunque yo me llame JUAN.
Pero eso sí, el maremágnum de pruebas correrá feliz por los mundos de yupi.
Otro tema a tener en cuenta, es, si es necesaria la prueba y cuando debemos realizar este tipo de pruebas ¿Qué estamos probando aquí?, no estamos haciendo un test de excepciones, ni un test de carga, ni un test de delegación etc., ni siquiera una prueba de integración, lo único que estamos haciendo es comprobar que el subsistema de SharePoint, responderá como nosotros esperamos que lo haga. (Cosa que los programadores de SharePoint hacemos habitualmente) De modo que garantizar que SharePoint funciona correctamente no es nuestra tarea. Para nosotros lo importante es el hecho de que interactuamos con un sistema externo y el ámbito de nuestras pruebas debería ser nuestro propio código.
Puede parecer complicado pero yo creo que hay que poner límites a las pruebas, de modo que probaría a ver si estoy controlando todas las excepciones que debería, a la hora de tratar con el subsistema y a asegurarme que los datos que le estoy pasando o que estoy recibiendo de él son los correctos.
Por otro lado cuando desarrollamos en el interior del subsistema (WebParts, Eventos, Workflows, etc.) las cosas pueden cambiar...
En Desarrolla con MSDN han publicado el Curso de Programación para SharePoint 2007 que a realizado Gustavo, sin duda un buen punto para comenzar. El curso es muy completo y además incluye videos.
1.1 Introducción a WSS y MOSS 1.2 Instalación de MOSS 1.3 Construcción de un sitio web basico 2.1 Integracion con ASP.NET 2.0 2.2 Modelo de Objetos 2.3 Paginas Maestras 2.4 WebParts 3.1 Que son Tipos de Contenido de Sitios 3.2 Desarrollo de Tipos de Contenido 3.3 Que son Columnas de Sitio 4.1 Introduccion a Caracteristicas 4.2 Uso de Caracteristicas 4.3 Estructura XML 4.4 Desarrollo de Caracteristicas 5.1 Introduccion a Flujos de Trabajo 5.2 Uso de Flujos de Trabajo 5.3 Creacion de Flujos de Trabajo 5.4 Flujos de Trabajo con SharePoint Designer 6.1 Introduccion al Catalogo de Datos Profesionales 6.2 Uso y Creacion del Catalogo de Datos Profesionales 6.3 Programacion del Catalogo de Datos Profesionales 7.1 Introduccion al Servicio de Excel 7.2 Uso del Servicio de Excel 7.3 Programacion con el Servicio de Excel
También os recuerdo que Gustavo, mantiene un PORTAL donde podéis encontrar cantidad de información sobre programación en SharePoint.
No pierdas el tiempo corre a verlo ...
Page 1 of 10 in the SharePoint-es category Next Page
|
Copyright © 2008 Carlos Segura. All rights reserved.
|
|