POST a testupdateview Actualiza el objeto existente y crea nuevo objeto -- django campo con django-forms campo con django-views campo con django-testing camp Relacionados El problema

POST to TestUpdateView updates existing object and creates new object


0
vote

problema

Español

Tengo una prueba para una visión de actualización que es:

  • actualizando el objeto existente
  • luego tratando de crear un nuevo objeto en blanco al mismo tiempo

Este comportamiento no sucede cuando ejecuto la vista en el navegador, por lo que es algo que ver con cómo se está ejecutando la prueba.

  • publicación a la URL de actualización
  • solicitud se ejecuta a través del updateview
  • form_valid () corre y hits instance.save()
  • , entonces algo está causando que se cree un segundo objeto justo después de ahorrar el objeto original

¿Alguna idea?

la prueba

  class TestReviewUpdateView(TestCase):      def setUp(self):         self.review = ReviewFactory()         self.submission = self.review.submission         self.factory = RequestFactory()         self.kwargs = {'submission_pk': self.submission.pk}      def test_form_valid_with_object(self):         self.request = self.factory.post(reverse(             'submissions:review_update', kwargs=self.kwargs))          # Create user         self.request.user = StaffFactory()          view = views.ReviewUpdateView()         view.request = self.request         view.object = self.review         kwargs = {             'scores': self.review.get_list_of_scores()         }         form = forms.ReviewForm(**kwargs)         form.cleaned_data = {'axe_0': '4', 'axe_1': '4', 'axe_2': '4'}         response = view.form_valid(form)         assert response.status_code == 302   

la vista

  class ReviewUpdateView(     BaseReviewForm,     UpdateView ):     """ A view for updating reviews. """      def dispatch(self, request, *args, **kwargs):         self.submission = self.get_submission()         self.conference = self.submission.conference         return super().dispatch(request, *args, **kwargs)  def get_submission(self):     return Submission.upcoming_objects.get_queryset(self.request.user).get(             pk=self.kwargs['submission_pk'])      def get_object(self):         return self.model.objects.get(             submission=self.submission,             user=self.request.user)      def get_form_kwargs(self):         kwargs = super().get_form_kwargs()         kwargs.update({             'scores': self.object.get_list_of_scores(),         })         return kwargs   def save_scores(self, form, instance):     for field in form.cleaned_data:         # The score fields will be numbers:         if "axe_" in field:             form_field = form.fields[field]             # Save the field's label as the key and score as value             instance.scores[form_field.label] = form.cleaned_data[field]     return instance      def form_valid(self, form):         instance = self.get_object()         instance = self.save_scores(form, instance)         instance.save()         return super().form_valid(form)   

la forma

  class ReviewForm(forms.ModelForm):     """ Form for new reviews of submissions """     class Meta:         model = Review         fields = []      def __init__(self, *args, **kwargs):         review_fields = kwargs.pop("review_fields")         scores = kwargs.pop("scores")         super().__init__(*args, **kwargs)         if review_fields:             for i in review_fields:                 self.fields["axe_%s" % i] = forms.ChoiceField(                     choices=NUMBER_CHOICES,                     label=review_fields[i],                     widget=forms.RadioSelect)                 if scores:                     self.fields["axe_%s" % i].initial = scores[int(i)]          self.helper = FormHelper()         self.helper.layout = Layout()         for i in review_fields:             self.helper.layout.fields.append(                 InlineRadios("axe_%s" % i)             )         self.helper.layout.fields.append(             ButtonHolder(                 Submit('submit', 'Submit', css_class='btn btn-primary')             )   

el modelo

  class Review(TimeStampedModel):     """ Review is a model for collecting answers from reviewers """     id = models.UUIDField(         primary_key=True,         default=uuid.uuid4,         editable=False,     )     user = models.ForeignKey(         get_user_model(),         null=False,         on_delete=models.PROTECT)     submission = models.ForeignKey(         Submission,         null=False,         on_delete=models.CASCADE     )     scores = JSONField(null=True, blank=True)     avg_score = models.DecimalField(max_digits=3, decimal_places=2, default=0)      class Meta:         unique_together = ("user", "submission")         ordering = ['-avg_score', '-created']      def save(self, *args, **kwargs):         self.avg_score = self.calc_avg_score()         import pdb; pdb.set_trace()         # save() is called twice and when it runs a second time, it errors because no values are set         super().save(*args, **kwargs)         self.submission.save()   

respuesta

@Dirkgroten me señaló en la dirección correcta. La solución de código es la siguiente -

  def test_form_valid_with_object(self):     user = User.objects.create_superuser('foo', 'myemail@test.com', 'bar')     self.review.user = user     self.review.save()     self.submission.conference.reviewers.add(user)     self.client.login(username='foo', password='bar')     response = self.client.post(         reverse('submissions:review_update', kwargs=self.kwargs),         data={'axe_0': '4', 'axe_1': '4', 'axe_2': '4'})     self.assertEqual(302, response.status_code)   
Original en ingles

I have a test for an UpdateView that is:

  • Updating the existing object
  • Then trying to create a new blank object at the same time

This behavior does not happen when I run through the view in the browser, so it is something to do with how the test is running.

  • POST to the update URL
  • Request runs through the UpdateView
  • Form_valid() runs and hits instance.save()
  • Then something is causing a second object to be created right after it saves the original object

Any ideas?

The Test

class TestReviewUpdateView(TestCase):      def setUp(self):         self.review = ReviewFactory()         self.submission = self.review.submission         self.factory = RequestFactory()         self.kwargs = {'submission_pk': self.submission.pk}      def test_form_valid_with_object(self):         self.request = self.factory.post(reverse(             'submissions:review_update', kwargs=self.kwargs))          # Create user         self.request.user = StaffFactory()          view = views.ReviewUpdateView()         view.request = self.request         view.object = self.review         kwargs = {             'scores': self.review.get_list_of_scores()         }         form = forms.ReviewForm(**kwargs)         form.cleaned_data = {'axe_0': '4', 'axe_1': '4', 'axe_2': '4'}         response = view.form_valid(form)         assert response.status_code == 302 

The View

class ReviewUpdateView(     BaseReviewForm,     UpdateView ):     """ A view for updating reviews. """      def dispatch(self, request, *args, **kwargs):         self.submission = self.get_submission()         self.conference = self.submission.conference         return super().dispatch(request, *args, **kwargs)  def get_submission(self):     return Submission.upcoming_objects.get_queryset(self.request.user).get(             pk=self.kwargs['submission_pk'])      def get_object(self):         return self.model.objects.get(             submission=self.submission,             user=self.request.user)      def get_form_kwargs(self):         kwargs = super().get_form_kwargs()         kwargs.update({             'scores': self.object.get_list_of_scores(),         })         return kwargs   def save_scores(self, form, instance):     for field in form.cleaned_data:         # The score fields will be numbers:         if "axe_" in field:             form_field = form.fields[field]             # Save the field's label as the key and score as value             instance.scores[form_field.label] = form.cleaned_data[field]     return instance      def form_valid(self, form):         instance = self.get_object()         instance = self.save_scores(form, instance)         instance.save()         return super().form_valid(form) 

The Form

class ReviewForm(forms.ModelForm):     """ Form for new reviews of submissions """     class Meta:         model = Review         fields = []      def __init__(self, *args, **kwargs):         review_fields = kwargs.pop("review_fields")         scores = kwargs.pop("scores")         super().__init__(*args, **kwargs)         if review_fields:             for i in review_fields:                 self.fields["axe_%s" % i] = forms.ChoiceField(                     choices=NUMBER_CHOICES,                     label=review_fields[i],                     widget=forms.RadioSelect)                 if scores:                     self.fields["axe_%s" % i].initial = scores[int(i)]          self.helper = FormHelper()         self.helper.layout = Layout()         for i in review_fields:             self.helper.layout.fields.append(                 InlineRadios("axe_%s" % i)             )         self.helper.layout.fields.append(             ButtonHolder(                 Submit('submit', 'Submit', css_class='btn btn-primary')             ) 

The Model

class Review(TimeStampedModel):     """ Review is a model for collecting answers from reviewers """     id = models.UUIDField(         primary_key=True,         default=uuid.uuid4,         editable=False,     )     user = models.ForeignKey(         get_user_model(),         null=False,         on_delete=models.PROTECT)     submission = models.ForeignKey(         Submission,         null=False,         on_delete=models.CASCADE     )     scores = JSONField(null=True, blank=True)     avg_score = models.DecimalField(max_digits=3, decimal_places=2, default=0)      class Meta:         unique_together = ("user", "submission")         ordering = ['-avg_score', '-created']      def save(self, *args, **kwargs):         self.avg_score = self.calc_avg_score()         import pdb; pdb.set_trace()         # save() is called twice and when it runs a second time, it errors because no values are set         super().save(*args, **kwargs)         self.submission.save() 

Answer

@dirkgroten pointed me in the right direction. The code solution is the following-

def test_form_valid_with_object(self):     user = User.objects.create_superuser('foo', 'myemail@test.com', 'bar')     self.review.user = user     self.review.save()     self.submission.conference.reviewers.add(user)     self.client.login(username='foo', password='bar')     response = self.client.post(         reverse('submissions:review_update', kwargs=self.kwargs),         data={'axe_0': '4', 'axe_1': '4', 'axe_2': '4'})     self.assertEqual(302, response.status_code) 
           
   
   

Lista de respuestas

1
 
vote
vote
La mejor respuesta
 

Estás haciendo esto de la manera incorrecta. Debe probar su forma y vistas en pruebas separadas.

Pruebe su formulario instantáneamente con data y NO instance para la creación de objetos y agregue el fn: async function ({ id }, exits) { res.set({ 'Content-disposition': `inline; filename="${id}"`, 'content-type': 'application/pdf', 'Access-Control-Allow-Origin': '*' }) const localPath = path.join(sails.config.custom.uploadDirectory, id) this.res.sendFile(localPath); } 0 para las actualizaciones de objetos. Compruebe la validez del formulario para la entrada válida y no válida. E.g:

  fn: async function ({ id }, exits) {  res.set({   'Content-disposition': `inline; filename="${id}"`,   'content-type': 'application/pdf',   'Access-Control-Allow-Origin': '*' })  const localPath = path.join(sails.config.custom.uploadDirectory, id) this.res.sendFile(localPath);  } 111  

Luego, pruebe sus puntos de vista solo haciendo una solicitud para ellos y pruebe la respuesta:

  fn: async function ({ id }, exits) {  res.set({   'Content-disposition': `inline; filename="${id}"`,   'content-type': 'application/pdf',   'Access-Control-Allow-Origin': '*' })  const localPath = path.join(sails.config.custom.uploadDirectory, id) this.res.sendFile(localPath);  } 2  
 

You're doing this the wrong way. You should test your form and views in separate tests.

Test your form by instantiating it with data and no instance for object creation and adding the instance for object updates. Check validity of form for valid and invalid input. E.g:

form = ReviewForm(data=kwargs, instance=self.submission) self.assertFalse(form.is_valid()) self.assertTrue(form.errors['some_field'])  # check some_field has an error 

Then test your views by just making a request to them and testing the response:

self.client.force_login(user) # if you test for logged in user response = self.client.post(url, data={...}) # this runs all your view code self.assertEqual(302, response.status_code)  # form was valid self.assertTrue(Review.objects.exists()) # or in case of invalid data self.assertEqual(200, response.status_code) self.assertTrue(response.context['form'].errors) 
 
 
         
         

Relacionados problema

0  Autenticación falló en la prueba de Django  ( Authentication failed in django test ) 
En Django Intenté crear un usuario y luego intenté iniciar sesión en ese usuario usando Selenium, pero cuando ejecuto la prueba falló, estaba mostrando un err...

14  Uso de cobertura, ¿cómo pruebo esta línea?  ( Using coverage how do i test this line ) 
Tengo una prueba simple: class ModelTests(TestCase): def test_method(self): instance = Activity(title="Test") self.assertEqual(instanc...

0  Django Selenium Select Form Opciones en <SELECT>  ( Django selenium select form options in select ) 
¿Cómo utiliza Selenium en Django para elegir y seleccionar una opción en una etiqueta import java.util.concurrent.*; import java.util.concurrent.locks.*; pu...

7  ¿Cómo puedo probar la lógica de validación de un formulario en un controlador de prueba de unidad en Django?  ( How can i test a forms validation logic in a unit test driver in django ) 
Quiero probar la porción is_valid de la lógica de validación de un formulario. En mi controlador de prueba tengo: test_animal = animal (nombre = "gato", n...

0  Unidad de prueba Django Modelo con una imagen - No de todo entiende SimpleuploaDEFILE  ( Unit testing django model with an image not quite understanding simpleuploaded ) 
Soy una prueba noob y estoy tratando de descubrir cómo escribir una prueba para confirmar que un formulario modelo es válido y generará una nueva instancia de...

29  Escribir buenas pruebas para aplicaciones de Django  ( Writing good tests for django applications ) 
Nunca he escrito ninguna prueba en mi vida, pero me gustaría comenzar a escribir pruebas para mis proyectos de Django. He leído algunos artículos sobre las pr...

1  Pruebas de Django: Mapeo de URL a la vista basada en clase  ( Django testing url mapping to the class based view ) 
Soy nuevo en las pruebas de Django, así que intentan los códigos de prueba básicos. Pero está mostrando un error en la segunda clase de prueba tests.py ...

2  Django prueba Ajax Endpoint en la vista  ( Django testing ajax endpoint in view ) 
Estoy usando django-ajax en una aplicación de django, y quiero hacer más minuciosos Pruebas de la unidad de la vista que lo usa. Mi plantilla para una vis...

1  Pruebas de Django de Multi-DB con enrutamiento automático  ( Django testing of multi db with automatic routing ) 
problema simple - Estoy usando multi-db éxito con la configuración enrutamiento automático Como se documenta en un DB heredado (que no están administrados...

1  Django-Non Rel + MongoDB error al ejecutar pruebas  ( Django nonrel mongodb error while running tests ) 
Tengo una configuración dentro de un entorno virtual: django-nol-1.6 mongodb-motor djangoteolbox Todo funciona bien, el único problema es dura...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos